diff --git a/jruby_executable/src/bin/jruby_build.rs b/jruby_executable/src/bin/jruby_build.rs index d311a61..8204709 100644 --- a/jruby_executable/src/bin/jruby_build.rs +++ b/jruby_executable/src/bin/jruby_build.rs @@ -1,4 +1,4 @@ -use bullet_stream::{Print, style}; +use bullet_stream::{global::print, style}; use clap::Parser; use fs_err::PathExt; use gem_version::GemVersion; @@ -14,6 +14,7 @@ use shared::{ use std::convert::From; use std::error::Error; use std::str::FromStr; +use std::time::Instant; static S3_BASE_URL: &str = "https://heroku-buildpack-ruby.s3.us-east-1.amazonaws.com"; @@ -32,7 +33,8 @@ fn jruby_build(args: &Args) -> Result<(), Box> { base_image, } = args; - let mut log = Print::new(std::io::stderr()).h1("Building JRuby"); + let start = Instant::now(); + print::h2("Building JRuby"); let inventory = source_dir().join("jruby_inventory.toml"); let volume_cache_dir = source_dir().join("cache"); let volume_output_dir = source_dir().join("output"); @@ -48,161 +50,137 @@ fn jruby_build(args: &Args) -> Result<(), Box> { TarDownloadPath(volume_cache_dir.join(format!("jruby-dist-{version}-bin.tar.gz"))); if download_path.as_ref().fs_err_try_exists()? { - log = log - .bullet(format!( - "Using cached JRuby archive {}", - download_path.as_ref().display() - )) - .done(); + print::bullet(format!( + "Using cached JRuby archive {}", + download_path.as_ref().display() + )); } else { let url = format!( "https://repo1.maven.org/maven2/org/jruby/jruby-dist/{version}/jruby-dist-{version}-bin.tar.gz" ); - let timer = log - .bullet("Download JRuby") - .sub_bullet(format!("To {}", download_path.as_ref().to_string_lossy())) - .sub_bullet(format!("From {}", style::url(&url))) - .start_timer("Downloading"); - download_tar(&url, &download_path)?; + print::bullet("Download JRuby"); + print::sub_bullet(format!("To {}", download_path.as_ref().to_string_lossy())); + print::sub_bullet(format!("From {}", style::url(&url))); - log = timer.done().done(); + let timer = print::sub_start_timer("Downloading"); + download_tar(&url, &download_path)?; + timer.done(); } untar_to_dir(&download_path, &extracted_path)?; let jruby_dir = extracted_path.join(format!("jruby-{version}")); - log = { - let mut bullet = log.bullet("Removing unnecessary files"); - for pattern in &["*.bat", "*.dll", "*.exe"] { - for path in glob::glob(&jruby_dir.join("bin").join(pattern).to_string_lossy())? - .collect::, _>>()? - { - bullet = bullet.sub_bullet(format!("Remove {}", path.display())); - fs_err::remove_file(path)?; - } + print::bullet("Removing unnecessary files"); + for pattern in &["*.bat", "*.dll", "*.exe"] { + for path in glob::glob(&jruby_dir.join("bin").join(pattern).to_string_lossy())? + .collect::, _>>()? + { + print::sub_bullet(format!("Remove {}", path.display())); + fs_err::remove_file(path)?; } + } - let path = jruby_dir.join("lib").join("target"); - if path.fs_err_try_exists()? { - bullet = bullet.sub_bullet(format!("Remove recursive {}", path.display())); - fs_err::remove_dir_all(&path)?; - } + let path = jruby_dir.join("lib").join("target"); + if path.fs_err_try_exists()? { + print::sub_bullet(format!("Remove recursive {}", path.display())); + fs_err::remove_dir_all(&path)?; + } - bullet.done() - }; - - log = { - let bullet = log.bullet("Checking for `ruby` binstub"); - let ruby_bin = jruby_dir.join("bin").join("ruby"); - if ruby_bin.fs_err_try_exists()? { - bullet.sub_bullet("File exists") - } else { - let sub = bullet.sub_bullet("Create ruby symlink to jruby"); - fs_err::os::unix::fs::symlink("jruby", ruby_bin)?; - sub - } - .done() - }; + print::bullet("Checking for `ruby` binstub"); + let ruby_bin = jruby_dir.join("bin").join("ruby"); + if ruby_bin.fs_err_try_exists()? { + print::sub_bullet("File exists") + } else { + print::sub_bullet("Create ruby symlink to jruby"); + fs_err::os::unix::fs::symlink("jruby", ruby_bin)?; + } let tgz_name = format!("ruby-{ruby_stdlib_version}-jruby-{version}.tgz"); - log = { - let mut bullet = log.bullet("Creating tgz archives"); - bullet = bullet.sub_bullet(format!( - "Inventory file {}", - style::value(inventory.to_string_lossy()) - )); - let tar_dir = volume_output_dir.join(base_image.to_string()); - - fs_err::create_dir_all(&tar_dir)?; - - let tar_file = fs_err::File::create(tar_dir.join(&tgz_name))?; - - let timer = bullet.start_timer(format!("Write {}", tar_file.path().display())); - tar_dir_to_file(&jruby_dir, &tar_file)?; - bullet = timer.done(); - - let tar_path = tar_file.path(); - let sha = sha256_from_path(tar_path)?; - let sha_seven = sha.chars().take(7).collect::(); - let sha_seven_path = append_filename_with(tar_path, &format!("-{sha_seven}"), ".tgz")?; - - bullet = bullet.sub_bullet(format!("Write {}", sha_seven_path.display(),)); - fs_err::copy(tar_file.path(), &sha_seven_path)?; - - let timestamp = chrono::Utc::now(); - for cpu_arch in [Arch::Amd64, Arch::Arm64] { - let distro_version = base_image.distro_version(); - let artifact = Artifact { - version: GemVersion::from_str(version)?, - os: inventory::artifact::Os::Linux, - arch: cpu_arch, - url: format!( - "{S3_BASE_URL}/{}", - sha_seven_path.strip_prefix(&volume_output_dir)?.display() - ), - checksum: format!("sha256:{sha}").parse()?, - metadata: ArtifactMetadata { - distro_version, - timestamp, - }, - }; - atomic_inventory_update(&inventory, |inventory| { - for prior in &inventory.artifacts { - if let Err(error) = artifact_same_url_different_checksum(prior, &artifact) { - // TODO: Investigate bullet stream ownership - println!( - "{}", - style::important(format!( - "!!!!!!!!!! Error updating inventory: {error}" - )) - ); - - fs_err::remove_file(&sha_seven_path)?; - return Err(error); - }; - } - - inventory - .artifacts - .retain(|a| artifact_is_different(a, &artifact)); - - inventory.push(artifact); - Ok(()) - })? - } + print::bullet("Creating tgz archives"); + print::sub_bullet(format!( + "Inventory file {}", + style::value(inventory.to_string_lossy()) + )); + let tar_dir = volume_output_dir.join(base_image.to_string()); + + fs_err::create_dir_all(&tar_dir)?; + + let tar_file = fs_err::File::create(tar_dir.join(&tgz_name))?; + + let timer = print::sub_start_timer(format!("Write {}", tar_file.path().display())); + tar_dir_to_file(&jruby_dir, &tar_file)?; + timer.done(); + + let tar_path = tar_file.path(); + let sha = sha256_from_path(tar_path)?; + let sha_seven = sha.chars().take(7).collect::(); + let sha_seven_path = append_filename_with(tar_path, &format!("-{sha_seven}"), ".tgz")?; + + print::sub_bullet(format!("Write {}", sha_seven_path.display(),)); + fs_err::copy(tar_file.path(), &sha_seven_path)?; + + let timestamp = chrono::Utc::now(); + for cpu_arch in [Arch::Amd64, Arch::Arm64] { + let distro_version = base_image.distro_version(); + let artifact = Artifact { + version: GemVersion::from_str(version)?, + os: inventory::artifact::Os::Linux, + arch: cpu_arch, + url: format!( + "{S3_BASE_URL}/{}", + sha_seven_path.strip_prefix(&volume_output_dir)?.display() + ), + checksum: format!("sha256:{sha}").parse()?, + metadata: ArtifactMetadata { + distro_version, + timestamp, + }, + }; + atomic_inventory_update(&inventory, |inventory| { + for prior in &inventory.artifacts { + if let Err(error) = artifact_same_url_different_checksum(prior, &artifact) { + print::error(format!("Error updating inventory\n\nError: {error}")); + + fs_err::remove_file(&sha_seven_path)?; + return Err(error); + }; + } - // Can be removed once manifest file support is fully rolled out - for cpu_arch in [Arch::Amd64, Arch::Arm64] { - let dir = volume_output_dir - .join(base_image.to_string()) - .join(cpu_arch.to_string()); - fs_err::create_dir_all(&dir)?; + inventory + .artifacts + .retain(|a| artifact_is_different(a, &artifact)); - let path = dir.join(&tgz_name); - bullet = bullet.sub_bullet(format!("Write {}", path.display())); - fs_err::copy(tar_file.path(), &path)?; - } + inventory.push(artifact); + Ok(()) + })? + } - bullet.done() - }; + // Can be removed once manifest file support is fully rolled out + for cpu_arch in [Arch::Amd64, Arch::Arm64] { + let dir = volume_output_dir + .join(base_image.to_string()) + .join(cpu_arch.to_string()); + fs_err::create_dir_all(&dir)?; - log.done(); + let path = dir.join(&tgz_name); + print::sub_bullet(format!("Write {}", path.display())); + fs_err::copy(tar_file.path(), &path)?; + } + print::all_done(&Some(start)); Ok(()) } fn main() { let args = Args::parse(); if let Err(error) = jruby_build(&args) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/jruby_executable/src/bin/jruby_changelog.rs b/jruby_executable/src/bin/jruby_changelog.rs index c861347..0062334 100644 --- a/jruby_executable/src/bin/jruby_changelog.rs +++ b/jruby_executable/src/bin/jruby_changelog.rs @@ -1,6 +1,6 @@ use std::error::Error; -use bullet_stream::Print; +use bullet_stream::global::print; use clap::Parser; use indoc::formatdoc; use jruby_executable::jruby_build_properties; @@ -32,7 +32,7 @@ fn jruby_changelog(args: &Args) -> Result<(), Box> { The JRuby release notes can be found on the [JRuby website](https://www.jruby.org/news). "}; - println!("{changelog}"); + print::plain(changelog); Ok(()) } @@ -40,13 +40,11 @@ fn jruby_changelog(args: &Args) -> Result<(), Box> { fn main() { let args = Args::parse(); if let Err(error) = jruby_changelog(&args) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } diff --git a/jruby_executable/src/bin/jruby_check.rs b/jruby_executable/src/bin/jruby_check.rs index faf7a20..9d7c481 100644 --- a/jruby_executable/src/bin/jruby_check.rs +++ b/jruby_executable/src/bin/jruby_check.rs @@ -1,12 +1,12 @@ -use bullet_stream::{Print, style}; +use bullet_stream::global::print; use clap::Parser; -use fun_run::CommandWithName; use indoc::formatdoc; use jruby_executable::jruby_build_properties; use libherokubuildpack::inventory::artifact::Arch; use shared::{BaseImage, source_dir}; use std::error::Error; use std::io::Write; +use std::time::Instant; use std::{path::PathBuf, process::Command}; static INNER_OUTPUT: &str = "/tmp/output"; @@ -33,7 +33,8 @@ fn jruby_check(args: &RubyArgs) -> Result<(), Box> { let jruby_stdlib_version = jruby_build_properties(version)?.ruby_stdlib_version()?; // Log progress to STDERR, print results to STDOUT directly - let mut log = Print::new(std::io::stderr()).h1(format!( + let start = Instant::now(); + print::h2(format!( "Prepare: Checking JRuby version ({version} linux/{arch} stdlib {jruby_stdlib_version}) for {base_image}", )); let distro_number = base_image.distro_number(); @@ -43,9 +44,7 @@ fn jruby_check(args: &RubyArgs) -> Result<(), Box> { let image_name = format!("heroku/jruby-builder:{base_image}"); - let mut stream = log - .bullet(format!("Dockerfile for {image_name}")) - .start_stream("Contents"); + print::bullet(format!("Dockerfile for {image_name}")); let dockerfile = formatdoc! {" FROM heroku/heroku:{distro_number}-build @@ -54,32 +53,23 @@ fn jruby_check(args: &RubyArgs) -> Result<(), Box> { RUN apt-get update -y; apt-get install default-jre default-jdk -y "}; - write!(stream, "{dockerfile}")?; + print::sub_stream_with("Contents", |mut stream, _| write!(stream, "{dockerfile}"))?; fs_err::write(&dockerfile_path, dockerfile)?; - log = stream.done().done(); - let outside_output = source_dir().join("output"); - log = { - let mut bullet = log.bullet(format!("Docker image {image_name}")); - let mut docker_build = Command::new("docker"); - docker_build.arg("build"); - docker_build.args(["--platform", &format!("linux/{arch}")]); - docker_build.args(["--progress", "plain"]); - docker_build.args(["--tag", &image_name]); - docker_build.args(["--file", &dockerfile_path.display().to_string()]); - docker_build.arg(source_dir().to_str().expect("Path to str")); - let _ = bullet.stream_with( - format!("Building via {}", style::command(docker_build.name())), - |stdout, stderr| docker_build.stream_output(stdout, stderr), - )?; - - bullet.done() - }; - - let (log, result) = { + print::bullet(format!("Docker image {image_name}")); + let mut docker_build = Command::new("docker"); + docker_build.arg("build"); + docker_build.args(["--platform", &format!("linux/{arch}")]); + docker_build.args(["--progress", "plain"]); + docker_build.args(["--tag", &image_name]); + docker_build.args(["--file", &dockerfile_path.display().to_string()]); + docker_build.arg(source_dir().to_str().expect("Path to str")); + print::sub_stream_cmd(docker_build)?; + + let output = { let inner_jruby_path = PathBuf::from(INNER_OUTPUT) .join(base_image.to_string()) .join(format!("ruby-{jruby_stdlib_version}-jruby-{version}.tgz")); @@ -110,36 +100,30 @@ fn jruby_check(args: &RubyArgs) -> Result<(), Box> { .join(" && "), ); - let mut cmd_stream = log.bullet("Versions"); + print::bullet("Versions"); - let result = cmd_stream.stream_with( - format!("Running {}", style::command(cmd.name())), - |stdout, stderr| cmd.stream_output(stdout, stderr), - )?; - - (cmd_stream.done(), result) + print::sub_stream_cmd(cmd)? }; - log.done(); - eprintln!(); + print::all_done(&Some(start)); + + print::plain(""); // Print results to STDOUT for github summary println!("## JRuby {version} stdlib {jruby_stdlib_version} linux/{arch} for {base_image}"); println!(); - println!("{}", result.stdout_lossy()); + println!("{}", output.stdout_lossy()); Ok(()) } fn main() { let args = RubyArgs::parse(); if let Err(error) = jruby_check(&args) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/ruby_executable/src/bin/ruby_build.rs b/ruby_executable/src/bin/ruby_build.rs index bd049f8..3d26940 100644 --- a/ruby_executable/src/bin/ruby_build.rs +++ b/ruby_executable/src/bin/ruby_build.rs @@ -1,7 +1,6 @@ -use bullet_stream::{Print, style}; +use bullet_stream::{global::print, style}; use clap::Parser; use fs_err::PathExt; -use fun_run::CommandWithName; use gem_version::GemVersion; use indoc::{formatdoc, indoc}; use libherokubuildpack::inventory::{ @@ -18,6 +17,7 @@ use std::{ path::{Path, PathBuf}, process::Command, str::FromStr, + time::Instant, }; static INNER_OUTPUT: &str = "/tmp/output"; @@ -64,7 +64,8 @@ fn ruby_build(args: &RubyArgs) -> Result<(), Box> { base_image, } = args; - let mut log = Print::new(std::io::stderr()).h1("Building Ruby"); + let start = Instant::now(); + print::h2("Building Ruby"); let inventory = source_dir().join("ruby_inventory.toml"); let volume_cache_dir = source_dir().join("cache"); let volume_output_dir = source_dir().join("output"); @@ -77,137 +78,110 @@ fn ruby_build(args: &RubyArgs) -> Result<(), Box> { let dockerfile = ruby_dockerfile_contents(base_image); let dockerfile_path = temp_dir.path().join("Dockerfile"); - log = { - let mut bullet = log.bullet("Dockerfile"); - bullet.stream_with("Writing contents to tmpdir", |mut stream, _| { - write!(stream, "{dockerfile}")?; - fs_err::write(&dockerfile_path, &dockerfile) - })?; - bullet.done() - }; - - log = { - let mut bullet = log.bullet(format!("Docker image {image_name}")); - let mut docker_build = Command::new("docker"); - docker_build.arg("build"); - docker_build.args(["--platform", &format!("linux/{arch}")]); - docker_build.args(["--progress", "plain"]); - docker_build.args(["--tag", &image_name]); - docker_build.args(["--file", &dockerfile_path.display().to_string()]); - docker_build.arg(source_dir()); - let _ = bullet.stream_with( - format!("Building via {}", style::command(docker_build.name())), - |stdout, stderr| docker_build.stream_output(stdout, stderr), - )?; - - bullet.done() - }; + print::bullet("Dockerfile"); + print::sub_stream_with("Writing contents to tmpdir", |mut stream, _| { + write!(stream, "{dockerfile}").and_then(|_| fs_err::write(&dockerfile_path, &dockerfile)) + })?; + + print::bullet(format!("Docker image {image_name}")); + let mut docker_build = Command::new("docker"); + docker_build.arg("build"); + docker_build.args(["--platform", &format!("linux/{arch}")]); + docker_build.args(["--progress", "plain"]); + docker_build.args(["--tag", &image_name]); + docker_build.args(["--file", &dockerfile_path.display().to_string()]); + docker_build.arg(source_dir()); + print::sub_stream_cmd(docker_build)?; let download_tar_path = TarDownloadPath(volume_cache_dir.join(format!("ruby-source-{version}.tgz"))); - log = if Path::fs_err_try_exists(download_tar_path.as_ref())? { - log.bullet(format!( + if Path::fs_err_try_exists(download_tar_path.as_ref())? { + print::bullet(format!( "Using cached tarball {}", download_tar_path.as_ref().display() )) - .done() } else { - let bullet = log.bullet(format!( + print::bullet(format!( "Downloading {version} to {}", download_tar_path.as_ref().display() )); download_tar(&version.download_url(), &download_tar_path)?; - bullet.done() }; - log = { - let mut bullet = log.bullet("Make Ruby"); - let input_tar = PathBuf::from(INNER_CACHE).join(format!("ruby-source-{version}.tgz")); - let output_tar = output_tar_path(Path::new(INNER_OUTPUT), version, base_image, arch); - let volume_cache = volume_cache_dir.display(); - let volume_output = volume_output_dir.display(); - - let mut docker_run = Command::new("docker"); - docker_run.arg("run"); - docker_run.arg("--rm"); - docker_run.args(["--platform", &format!("linux/{arch}")]); - docker_run.args(["--volume", &format!("{volume_output}:{INNER_OUTPUT}")]); - docker_run.args(["--volume", &format!("{volume_cache}:{INNER_CACHE}")]); - - docker_run.arg(&image_name); - docker_run.args(["bash", "-c"]); - docker_run.arg(format!( - "./make_ruby.sh {} {}", - input_tar.display(), - output_tar.display() - )); - - bullet.stream_with( - format!("Running {}", style::command(docker_run.name())), - |stdout, stderr| docker_run.stream_output(stdout, stderr), - )?; - bullet.done() + print::bullet("Make Ruby"); + let input_tar = PathBuf::from(INNER_CACHE).join(format!("ruby-source-{version}.tgz")); + let output_tar = output_tar_path(Path::new(INNER_OUTPUT), version, base_image, arch); + let volume_cache = volume_cache_dir.display(); + let volume_output = volume_output_dir.display(); + + let mut docker_run = Command::new("docker"); + docker_run.arg("run"); + docker_run.arg("--rm"); + docker_run.args(["--platform", &format!("linux/{arch}")]); + docker_run.args(["--volume", &format!("{volume_output}:{INNER_OUTPUT}")]); + docker_run.args(["--volume", &format!("{volume_cache}:{INNER_CACHE}")]); + + docker_run.arg(&image_name); + docker_run.args(["bash", "-c"]); + docker_run.arg(format!( + "./make_ruby.sh {} {}", + input_tar.display(), + output_tar.display() + )); + + print::sub_stream_cmd(docker_run)?; + + print::bullet(format!( + "Updating manifest {}", + style::value(inventory.to_string_lossy()) + )); + + let output_tar = output_tar_path(&volume_output_dir, version, base_image, arch); + + let sha = sha256_from_path(&output_tar)?; + let sha_seven = sha.chars().take(7).collect::(); + let sha_seven_path = append_filename_with(&output_tar, &format!("-{sha_seven}"), ".tgz")?; + let url = format!( + "{S3_BASE_URL}/{}", + sha_seven_path.strip_prefix(&volume_output_dir)?.display() + ); + + print::sub_bullet(format!("Copying SHA tgz {}", sha_seven_path.display(),)); + fs_err::copy(output_tar, &sha_seven_path)?; + + let artifact = Artifact { + version: GemVersion::from_str(&version.bundler_format())?, + os: inventory::artifact::Os::Linux, + arch: *arch, + url, + checksum: format!("sha256:{sha}").parse()?, + metadata: ArtifactMetadata { + distro_version: base_image.distro_version(), + timestamp: chrono::Utc::now(), + }, }; - log = { - let mut bullet = log.bullet(format!( - "Updating manifest {}", - style::value(inventory.to_string_lossy()) - )); + atomic_inventory_update(&inventory, |inventory| { + for prior in &inventory.artifacts { + if let Err(error) = artifact_same_url_different_checksum(prior, &artifact) { + print::error(format!("Error updating inventory\n\nError: {error}")); - let output_tar = output_tar_path(&volume_output_dir, version, base_image, arch); - - let sha = sha256_from_path(&output_tar)?; - let sha_seven = sha.chars().take(7).collect::(); - let sha_seven_path = append_filename_with(&output_tar, &format!("-{sha_seven}"), ".tgz")?; - let url = format!( - "{S3_BASE_URL}/{}", - sha_seven_path.strip_prefix(&volume_output_dir)?.display() - ); - - bullet = bullet.sub_bullet(format!("Copying SHA tgz {}", sha_seven_path.display(),)); - fs_err::copy(output_tar, &sha_seven_path)?; - - let artifact = Artifact { - version: GemVersion::from_str(&version.bundler_format())?, - os: inventory::artifact::Os::Linux, - arch: *arch, - url, - checksum: format!("sha256:{sha}").parse()?, - metadata: ArtifactMetadata { - distro_version: base_image.distro_version(), - timestamp: chrono::Utc::now(), - }, - }; - - atomic_inventory_update(&inventory, |inventory| { - for prior in &inventory.artifacts { - if let Err(error) = artifact_same_url_different_checksum(prior, &artifact) { - // TODO: Investigate bullet stream ownership - println!( - "{}", - style::important(format!("!!!!!!!!!! Error updating inventory: {error}")) - ); - - fs_err::remove_file(&sha_seven_path)?; - return Err(error); - }; - } - - inventory - .artifacts - .retain(|a| artifact_is_different(a, &artifact)); - - inventory.push(artifact); - - Ok(()) - })?; - - bullet.done() - }; + fs_err::remove_file(&sha_seven_path)?; + return Err(error); + }; + } + + inventory + .artifacts + .retain(|a| artifact_is_different(a, &artifact)); + + inventory.push(artifact); + + Ok(()) + })?; - log.done(); + print::all_done(&Some(start)); Ok(()) } @@ -215,13 +189,11 @@ fn ruby_build(args: &RubyArgs) -> Result<(), Box> { fn main() { let args = RubyArgs::parse(); if let Err(error) = ruby_build(&args) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/ruby_executable/src/bin/ruby_changelog.rs b/ruby_executable/src/bin/ruby_changelog.rs index 3edcc75..ff7c71c 100644 --- a/ruby_executable/src/bin/ruby_changelog.rs +++ b/ruby_executable/src/bin/ruby_changelog.rs @@ -1,6 +1,6 @@ use std::{error::Error, io::Write}; -use bullet_stream::Print; +use bullet_stream::global::print; use clap::Parser; use indoc::formatdoc; use shared::RubyDownloadVersion; @@ -58,13 +58,11 @@ where fn main() { let args = Args::parse(); if let Err(error) = ruby_changelog(&args, std::io::stdout()) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/ruby_executable/src/bin/ruby_check.rs b/ruby_executable/src/bin/ruby_check.rs index 1002dd0..8c7a95c 100644 --- a/ruby_executable/src/bin/ruby_check.rs +++ b/ruby_executable/src/bin/ruby_check.rs @@ -1,10 +1,9 @@ -use bullet_stream::{Print, style}; +use bullet_stream::global::print; use clap::Parser; -use fun_run::CommandWithName; use indoc::formatdoc; use libherokubuildpack::inventory::artifact::Arch; use shared::{BaseImage, RubyDownloadVersion, output_tar_path, source_dir}; -use std::{error::Error, path::PathBuf, process::Command}; +use std::{error::Error, path::PathBuf, process::Command, time::Instant}; static INNER_OUTPUT: &str = "/tmp/output"; @@ -26,7 +25,8 @@ fn ruby_check(args: &RubyArgs) -> Result<(), Box> { version, base_image, } = args; - let log = Print::new(std::io::stderr()).h1(format!( + let start = Instant::now(); + print::h2(format!( "Checking Ruby version ({version} linux/{arch}) for {base_image}", )); let path = output_tar_path(&PathBuf::from(INNER_OUTPUT), version, base_image, arch); @@ -60,20 +60,16 @@ fn ruby_check(args: &RubyArgs) -> Result<(), Box> { .join(" && "), ); - let mut cmd_stream = log.bullet("Versions"); + print::bullet("Versions"); + let output = print::sub_stream_cmd(cmd)?; - let result = cmd_stream.stream_with( - format!("Running {}", style::command(cmd.name())), - |stdout, stderr| cmd.stream_output(stdout, stderr), - )?; - - cmd_stream.done().done(); - eprintln!(); + print::all_done(&Some(start)); + print::plain(""); // Print results to STDOUT for github summary println!("## Ruby {version} linux/{arch} for {base_image}"); println!(); - println!("{}", result.stdout_lossy()); + println!("{}", output.stdout_lossy()); Ok(()) } @@ -81,13 +77,11 @@ fn ruby_check(args: &RubyArgs) -> Result<(), Box> { fn main() { let args = RubyArgs::parse(); if let Err(error) = ruby_check(&args) { - Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/shared/src/bin/inventory_check.rs b/shared/src/bin/inventory_check.rs index e42951b..3f8df3b 100644 --- a/shared/src/bin/inventory_check.rs +++ b/shared/src/bin/inventory_check.rs @@ -1,3 +1,4 @@ +use bullet_stream::global::print; use clap::Parser; use indoc::formatdoc; use shared::inventory_check; @@ -17,13 +18,11 @@ fn check(path: &Path) -> Result<(), Box> { fn main() { let args = Args::parse(); if let Err(error) = check(&args.path) { - bullet_stream::Print::new(std::io::stderr()) - .without_header() - .error(formatdoc! {" - ❌ Command failed ❌ + print::error(formatdoc! {" + ❌ Command failed ❌ - {error} - "}); + {error} + "}); std::process::exit(1); } } diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 6487910..9112ca3 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1,9 +1,6 @@ -use bullet_stream::Print; -use bullet_stream::state::SubBullet; use fs_err::{File, PathExt}; use fun_run::CommandWithName; use libherokubuildpack::inventory::artifact::Arch; -use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -184,51 +181,6 @@ pub fn tar_dir_to_file(compiled_dir: &Path, tar_file: &File) -> Result<(), Error Ok(()) } -// # Binstubs have a "shebang" on the first line that tells the OS -// # how to execute the file if it's called directly i.e. `$ ./script.rb` instead -// # of `$ ruby ./script.rb`. -// # -// # We need the shebang to be portable (not use an absolute path) so we check -// # for any ruby shebang lines and replace them with `#!/usr/bin/env ruby` -// # which translates to telling the os "Use the `ruby` executable from the same -// location as `which ruby`" to run this program. -pub fn update_shebangs_in_dir( - mut log: Print>, - path: &Path, -) -> Result>, Error> -where - W: Send + Write + Sync + 'static, -{ - let dir = fs_err::read_dir(path).map_err(Error::FsError)?; - for entry in dir { - let entry = entry.map_err(Error::FsError)?; - let entry_path = entry.path(); - if entry_path.is_file() { - let mut file = fs_err::OpenOptions::new() - .read(true) - .write(true) - .open(&entry_path) - .map_err(Error::FsError)?; - let mut contents = String::new(); - - log = log.sub_bullet(format!("Reading {}", entry_path.display())); - if file.read_to_string(&mut contents).is_ok() { - if let Some(contents) = update_shebang(contents) { - log = log.sub_bullet(format!("Updating shebang in {}", entry_path.display())); - file.seek(SeekFrom::Start(0)).map_err(Error::FsError)?; - file.write_all(contents.as_bytes()) - .map_err(Error::FsError)?; - } else { - log = log.sub_bullet("Skipping (no ruby shebang found)"); - } - } else { - log = log.sub_bullet("Skipping (possibly binary file)"); - } - } - } - Ok(log) -} - pub fn update_shebang(contents: String) -> Option { if let Some(shebang) = contents.lines().next() { if shebang.starts_with("#!") && shebang.contains("/ruby") { @@ -244,6 +196,7 @@ pub fn update_shebang(contents: String) -> Option { #[cfg(test)] mod test { use super::*; + use std::io::Read; use std::str::FromStr; use std::thread; use tempfile::tempdir; @@ -273,23 +226,6 @@ mod test { assert_eq!(updated_contents, None); } - #[test] - fn test_update_shebangs_in_dir() { - let dir = tempfile::tempdir().unwrap(); - let file_path = dir.path().join("script.rb"); - - let mut file = File::create(&file_path).unwrap(); - writeln!(file, "#!/path/to/ruby\nprint 'Hello, world!'").unwrap(); - - let log = Print::new(std::io::stdout()) - .without_header() - .bullet("shebangs"); - _ = update_shebangs_in_dir(log, dir.path()).unwrap(); - - let contents = fs_err::read_to_string(&file_path).unwrap(); - assert_eq!(contents, "#!/usr/bin/env ruby\nprint 'Hello, world!'\n"); - } - #[test] fn test_validate_version_for_stack() { assert!(