Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
46c070d
Introduce function style print
schneems Nov 17, 2025
f924d19
Function style print interface
schneems Nov 17, 2025
74336a4
Function style print interface
schneems Nov 17, 2025
36b3a79
Function style print interface
schneems Nov 17, 2025
4c0421b
Function style print interface
schneems Nov 17, 2025
1d600b7
Remove unused assignment
schneems Nov 17, 2025
235e9cd
Remove unused assignment
schneems Nov 17, 2025
1f58bcd
Remove unused assignment
schneems Nov 17, 2025
7d03a5a
Remove Print struct
schneems Nov 17, 2025
9cf79a1
Remove Print struct
schneems Nov 17, 2025
e04002c
Prefer print over println
schneems Nov 17, 2025
7992919
Remove struct usage
schneems Nov 17, 2025
0e81b51
Remove struct usage
schneems Nov 17, 2025
e61b61b
Remove struct usage
schneems Nov 17, 2025
cfeb103
Remove struct usage
schneems Nov 17, 2025
cfe0446
Remove struct usage
schneems Nov 17, 2025
d85b01b
Prefer print over println
schneems Nov 17, 2025
75a6983
Function print interface
schneems Nov 17, 2025
96f0a03
Function print interface
schneems Nov 17, 2025
900030d
Function print interface
schneems Nov 17, 2025
ef5a161
Function print interface
schneems Nov 17, 2025
3c30240
Remove unused assignment
schneems Nov 17, 2025
babb1b0
Remove unused imports
schneems Nov 17, 2025
6f615df
Use print interface
schneems Nov 17, 2025
e4b284e
Use print interface
schneems Nov 17, 2025
05a16a3
Use print interface
schneems Nov 17, 2025
944847f
Use print interface
schneems Nov 17, 2025
8ec927e
Use print interface
schneems Nov 17, 2025
efc7c83
Use print interface
schneems Nov 17, 2025
8245091
Use print interface
schneems Nov 17, 2025
6d161ec
Remove unused assignments
schneems Nov 17, 2025
e4c6feb
Prefer print function
schneems Nov 17, 2025
2a07809
Prefer print function
schneems Nov 17, 2025
a0e86d3
Prefer print function
schneems Nov 17, 2025
987e38a
Remove unused function
schneems Nov 17, 2025
091b090
Add accidentally removed bullet
schneems Nov 18, 2025
d52a788
Address TODO comment
schneems Nov 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 106 additions & 128 deletions jruby_executable/src/bin/jruby_build.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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";

Expand All @@ -32,7 +33,8 @@ fn jruby_build(args: &Args) -> Result<(), Box<dyn Error>> {
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");
Expand All @@ -48,161 +50,137 @@ fn jruby_build(args: &Args) -> Result<(), Box<dyn Error>> {
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::<Result<Vec<_>, _>>()?
{
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::<Result<Vec<_>, _>>()?
{
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::<String>();
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::<String>();
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);
}
}
14 changes: 6 additions & 8 deletions jruby_executable/src/bin/jruby_changelog.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -32,21 +32,19 @@ fn jruby_changelog(args: &Args) -> Result<(), Box<dyn Error>> {
The JRuby release notes can be found on the [JRuby website](https://www.jruby.org/news).
"};

println!("{changelog}");
print::plain(changelog);

Ok(())
}

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);
}
Expand Down
Loading