Skip to content

Commit ef4af81

Browse files
authored
Use global print output (#395)
* Use global writer state This preserves newlines between when the printer is dropped and then recovered. * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Make Print interfaces generic * Update example to not need print state in signature * Remove unused import * Update integration tests Stdout -> Stderr
1 parent 16c9983 commit ef4af81

13 files changed

+122
-87
lines changed

buildpacks/ruby/src/gem_list.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use fun_run::CmdError;
55
use regex::Regex;
66
use std::collections::HashMap;
77
use std::ffi::OsStr;
8-
use std::io::Stdout;
8+
use std::io::Write;
99
use std::process::Command;
1010

1111
/// ## Gets list of an application's dependencies
@@ -21,11 +21,12 @@ pub(crate) struct GemList {
2121
/// # Errors
2222
///
2323
/// Errors if the command `bundle list` is unsuccessful.
24-
pub(crate) fn bundle_list<T, K, V>(
25-
mut bullet: Print<SubBullet<Stdout>>,
24+
pub(crate) fn bundle_list<W, T, K, V>(
25+
mut bullet: Print<SubBullet<W>>,
2626
envs: T,
27-
) -> Result<(Print<SubBullet<Stdout>>, GemList), CmdError>
27+
) -> Result<(Print<SubBullet<W>>, GemList), CmdError>
2828
where
29+
W: Write + Send + Sync + 'static,
2930
T: IntoIterator<Item = (K, V)>,
3031
K: AsRef<OsStr>,
3132
V: AsRef<OsStr>,

buildpacks/ruby/src/layers/bundle_download_layer.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,19 @@ use libcnb::layer_env::{LayerEnv, ModificationBehavior, Scope};
1818
use libcnb::Env;
1919
use magic_migrate::TryMigrate;
2020
use serde::{Deserialize, Serialize};
21-
use std::io::Stdout;
21+
use std::io::Write;
2222
use std::path::Path;
2323
use std::process::Command;
2424

25-
pub(crate) fn handle(
25+
pub(crate) fn handle<W>(
2626
context: &libcnb::build::BuildContext<RubyBuildpack>,
2727
env: &Env,
28-
mut bullet: Print<SubBullet<Stdout>>,
28+
mut bullet: Print<SubBullet<W>>,
2929
metadata: &Metadata,
30-
) -> libcnb::Result<(Print<SubBullet<Stdout>>, LayerEnv), RubyBuildpackError> {
30+
) -> libcnb::Result<(Print<SubBullet<W>>, LayerEnv), RubyBuildpackError>
31+
where
32+
W: Write + Send + Sync + 'static,
33+
{
3134
let layer_ref = DiffMigrateLayer {
3235
build: true,
3336
launch: true,
@@ -79,12 +82,15 @@ pub(crate) struct MetadataV1 {
7982
pub(crate) version: ResolvedBundlerVersion,
8083
}
8184

82-
fn download_bundler(
83-
mut bullet: Print<SubBullet<Stdout>>,
85+
fn download_bundler<W>(
86+
mut bullet: Print<SubBullet<W>>,
8487
env: &Env,
8588
metadata: &Metadata,
8689
gem_path: &Path,
87-
) -> Result<Print<SubBullet<Stdout>>, RubyBuildpackError> {
90+
) -> Result<Print<SubBullet<W>>, RubyBuildpackError>
91+
where
92+
W: Write + Send + Sync + 'static,
93+
{
8894
let bin_dir = gem_path.join("bin");
8995

9096
let mut cmd = Command::new("gem");

buildpacks/ruby/src/layers/bundle_install_layer.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use libcnb::{
3232
};
3333
use magic_migrate::TryMigrate;
3434
use serde::{Deserialize, Serialize};
35-
use std::io::Stdout;
35+
use std::io::Write;
3636
use std::{path::Path, process::Command};
3737

3838
/// When this environment variable is set, the `bundle install` command will always
@@ -44,13 +44,16 @@ const SKIP_DIGEST_ENV_KEY: &str = "HEROKU_SKIP_BUNDLE_DIGEST";
4444
/// on the next build.
4545
pub(crate) const FORCE_BUNDLE_INSTALL_CACHE_KEY: &str = "v1";
4646

47-
pub(crate) fn handle(
47+
pub(crate) fn handle<W>(
4848
context: &libcnb::build::BuildContext<RubyBuildpack>,
4949
env: &Env,
50-
mut bullet: Print<SubBullet<Stdout>>,
50+
mut bullet: Print<SubBullet<W>>,
5151
metadata: &Metadata,
5252
without: &BundleWithout,
53-
) -> libcnb::Result<(Print<SubBullet<Stdout>>, LayerEnv), RubyBuildpackError> {
53+
) -> libcnb::Result<(Print<SubBullet<W>>, LayerEnv), RubyBuildpackError>
54+
where
55+
W: Write + Send + Sync + 'static,
56+
{
5457
let layer_ref = DiffMigrateLayer {
5558
build: true,
5659
launch: true,

buildpacks/ruby/src/layers/metrics_agent_install.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use libcnb::layer::{
99
};
1010
use libherokubuildpack::digest::sha256;
1111
use serde::{Deserialize, Serialize};
12-
use std::io::Stdout;
12+
use std::io::Write;
1313
use std::os::unix::fs::PermissionsExt;
1414
use std::path::{Path, PathBuf};
1515
use tar::Archive;
@@ -60,10 +60,13 @@ pub(crate) enum MetricsAgentInstallError {
6060
ChecksumFailed(String),
6161
}
6262

63-
pub(crate) fn handle_metrics_agent_layer(
63+
pub(crate) fn handle_metrics_agent_layer<W>(
6464
context: &libcnb::build::BuildContext<RubyBuildpack>,
65-
mut bullet: Print<SubBullet<Stdout>>,
66-
) -> libcnb::Result<Print<SubBullet<Stdout>>, RubyBuildpackError> {
65+
mut bullet: Print<SubBullet<W>>,
66+
) -> libcnb::Result<Print<SubBullet<W>>, RubyBuildpackError>
67+
where
68+
W: Write + Send + Sync + 'static,
69+
{
6770
let metadata = Metadata {
6871
download_url: DOWNLOAD_URL.to_string(),
6972
};

buildpacks/ruby/src/layers/ruby_install_layer.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,20 @@ use libcnb::layer::{EmptyLayerCause, LayerState};
2727
use libcnb::layer_env::LayerEnv;
2828
use magic_migrate::TryMigrate;
2929
use serde::{Deserialize, Serialize};
30-
use std::io::{self, Stdout};
30+
use std::io::Write;
3131
use std::path::Path;
3232
use tar::Archive;
3333
use tempfile::NamedTempFile;
3434
use url::Url;
3535

36-
pub(crate) fn handle(
36+
pub(crate) fn handle<W>(
3737
context: &libcnb::build::BuildContext<RubyBuildpack>,
38-
mut bullet: Print<SubBullet<Stdout>>,
38+
mut bullet: Print<SubBullet<W>>,
3939
metadata: &Metadata,
40-
) -> libcnb::Result<(Print<SubBullet<Stdout>>, LayerEnv), RubyBuildpackError> {
40+
) -> libcnb::Result<(Print<SubBullet<W>>, LayerEnv), RubyBuildpackError>
41+
where
42+
W: Write + Send + Sync + 'static,
43+
{
4144
let layer_ref = DiffMigrateLayer {
4245
build: true,
4346
launch: true,
@@ -198,7 +201,7 @@ pub(crate) fn download(
198201
let mut destination_file = fs_err::File::create(destination.as_ref())
199202
.map_err(RubyInstallError::CouldNotCreateDestinationFile)?;
200203

201-
io::copy(&mut response_reader, &mut destination_file)
204+
std::io::copy(&mut response_reader, &mut destination_file)
202205
.map_err(RubyInstallError::CouldNotWriteDestinationFile)?;
203206

204207
Ok(())

buildpacks/ruby/src/main.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use libcnb::layer::UncachedLayerDefinition;
1818
use libcnb::layer_env::{LayerEnv, ModificationBehavior, Scope};
1919
use libcnb::Platform;
2020
use libcnb::{buildpack_main, Buildpack};
21-
use std::io::stdout;
2221

2322
mod gem_list;
2423
mod layers;
@@ -115,7 +114,7 @@ impl Buildpack for RubyBuildpack {
115114

116115
#[allow(clippy::too_many_lines)]
117116
fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
118-
let mut build_output = Print::new(stdout()).h2("Heroku Ruby Buildpack");
117+
let mut build_output = Print::global().h2("Heroku Ruby Buildpack");
119118

120119
// ## Set default environment
121120
let (mut env, store) =

buildpacks/ruby/src/rake_task_detect.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bullet_stream::{state::SubBullet, Print};
22
use core::str::FromStr;
33
use fun_run::CmdError;
4-
use std::io::Stdout;
4+
use std::io::Write;
55
use std::{ffi::OsStr, process::Command};
66

77
/// Run `rake -P` and parse output to show what rake tasks an application has
@@ -21,11 +21,17 @@ pub(crate) struct RakeDetect {
2121
/// # Errors
2222
///
2323
/// Will return `Err` if `bundle exec rake -p` command cannot be invoked by the operating system.
24-
pub(crate) fn call<T: IntoIterator<Item = (K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr>>(
25-
mut bullet: Print<SubBullet<Stdout>>,
24+
pub(crate) fn call<W, T, K, V>(
25+
mut bullet: Print<SubBullet<W>>,
2626
envs: T,
2727
error_on_failure: bool,
28-
) -> Result<(Print<SubBullet<Stdout>>, RakeDetect), CmdError> {
28+
) -> Result<(Print<SubBullet<W>>, RakeDetect), CmdError>
29+
where
30+
W: Write + Send + Sync + 'static,
31+
T: IntoIterator<Item = (K, V)>,
32+
K: AsRef<OsStr>,
33+
V: AsRef<OsStr>,
34+
{
2935
let mut cmd = Command::new("rake");
3036
cmd.args(["-P", "--trace"]).env_clear().envs(envs);
3137

buildpacks/ruby/src/steps/detect_rake_tasks.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ use bullet_stream::state::SubBullet;
77
use bullet_stream::{style, Print};
88
use libcnb::build::BuildContext;
99
use libcnb::Env;
10-
use std::io::Stdout;
10+
use std::io::Write;
1111

12-
pub(crate) fn detect_rake_tasks(
13-
bullet: Print<SubBullet<Stdout>>,
12+
pub(crate) fn detect_rake_tasks<W>(
13+
bullet: Print<SubBullet<W>>,
1414
gem_list: &GemList,
1515
context: &BuildContext<RubyBuildpack>,
1616
env: &Env,
17-
) -> Result<(Print<SubBullet<Stdout>>, Option<RakeDetect>), RubyBuildpackError> {
17+
) -> Result<(Print<SubBullet<W>>, Option<RakeDetect>), RubyBuildpackError>
18+
where
19+
W: Write + Send + Sync + 'static,
20+
{
1821
let help = style::important("HELP");
1922
let rake = style::value("rake");
2023
let gemfile = style::value("Gemfile");

buildpacks/ruby/src/steps/get_default_process.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ use libcnb::build::BuildContext;
66
use libcnb::data::launch::Process;
77
use libcnb::data::launch::ProcessBuilder;
88
use libcnb::data::process_type;
9-
use std::io::Stdout;
9+
use std::io::Write;
1010
use std::path::Path;
1111

12-
pub(crate) fn get_default_process(
13-
bullet: Print<SubBullet<Stdout>>,
12+
pub(crate) fn get_default_process<W>(
13+
bullet: Print<SubBullet<W>>,
1414
context: &BuildContext<RubyBuildpack>,
1515
gem_list: &GemList,
16-
) -> (Print<SubBullet<Stdout>>, Option<Process>) {
16+
) -> (Print<SubBullet<W>>, Option<Process>)
17+
where
18+
W: Write + Send + Sync + 'static,
19+
{
1720
let config_ru = style::value("config.ru");
1821
let rails = style::value("rails");
1922
let rack = style::value("rack");

buildpacks/ruby/src/steps/rake_assets_install.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ use bullet_stream::{style, Print};
66
use commons::cache::{mib, AppCache, CacheConfig, CacheError, CacheState, KeepPath, PathState};
77
use libcnb::build::BuildContext;
88
use libcnb::Env;
9-
use std::io::Stdout;
9+
use std::io::Write;
1010
use std::process::Command;
1111

12-
pub(crate) fn rake_assets_install(
13-
mut bullet: Print<SubBullet<Stdout>>,
12+
pub(crate) fn rake_assets_install<W>(
13+
mut bullet: Print<SubBullet<W>>,
1414
context: &BuildContext<RubyBuildpack>,
1515
env: &Env,
1616
rake_detect: &RakeDetect,
17-
) -> Result<Print<SubBullet<Stdout>>, RubyBuildpackError> {
17+
) -> Result<Print<SubBullet<W>>, RubyBuildpackError>
18+
where
19+
W: Write + Send + Sync + 'static,
20+
{
1821
let help = style::important("HELP");
1922
let cases = asset_cases(rake_detect);
2023
let rake_assets_precompile = style::value("rake assets:precompile");

buildpacks/ruby/src/user_errors.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use crate::{DetectError, RubyBuildpackError};
22
use bullet_stream::{state::Bullet, state::SubBullet, style, Print};
33
use fun_run::CmdError;
44
use indoc::formatdoc;
5-
use std::io::Stdout;
5+
use std::io::Write;
66
use std::process::Command;
77
const DEBUG_INFO_STR: &str = "Debug info";
88

99
pub(crate) fn on_error(err: libcnb::Error<RubyBuildpackError>) {
10-
let output = Print::new(std::io::stdout()).without_header();
10+
let output = Print::global().without_header();
1111
let debug_info = style::important(DEBUG_INFO_STR);
1212
match cause(err) {
1313
Cause::OurError(error) => log_our_error(output, error),
@@ -34,7 +34,10 @@ pub(crate) fn on_error(err: libcnb::Error<RubyBuildpackError>) {
3434
}
3535

3636
#[allow(clippy::too_many_lines)]
37-
fn log_our_error(mut output: Print<Bullet<Stdout>>, error: RubyBuildpackError) {
37+
fn log_our_error<W: Write + Send + Sync + 'static>(
38+
mut output: Print<Bullet<W>>,
39+
error: RubyBuildpackError,
40+
) {
3841
let git_branch_url =
3942
style::url("https://devcenter.heroku.com/articles/git#deploy-from-a-branch-besides-main");
4043
let ruby_versions_url =
@@ -340,7 +343,10 @@ fn replace_app_path_with_relative(contents: impl AsRef<str>) -> String {
340343
app_path_re.replace_all(contents.as_ref(), "./").to_string()
341344
}
342345

343-
fn debug_cmd(mut log: Print<SubBullet<Stdout>>, command: &mut Command) -> Print<Bullet<Stdout>> {
346+
fn debug_cmd<W: Write + Send + Sync + 'static>(
347+
mut log: Print<SubBullet<W>>,
348+
command: &mut Command,
349+
) -> Print<Bullet<W>> {
344350
match log.stream_cmd(command) {
345351
Ok(_) => log.done(),
346352
Err(e) => log.sub_bullet(e.to_string()).done(),

0 commit comments

Comments
 (0)