diff --git a/Cargo.lock b/Cargo.lock index fe75f4b8..6f782069 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,28 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +[[package]] +name = "cache_diff" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2afc054cd5e2f8a0fb0122db671c3731849b1fcc86ec664e1031834a0828b84b" +dependencies = [ + "bullet_stream", + "cache_diff_derive", +] + +[[package]] +name = "cache_diff_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273bbd860603cb240372b460f8dc2440528ba95593f944b549194eb8600285a8" +dependencies = [ + "proc-macro2", + "quote", + "strum", + "syn 2.0.90", +] + [[package]] name = "camino" version = "1.1.6" @@ -571,6 +593,7 @@ name = "heroku-ruby-buildpack" version = "0.0.0" dependencies = [ "bullet_stream", + "cache_diff", "clap", "commons", "flate2", @@ -1307,6 +1330,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "ryu" version = "1.0.17" @@ -1425,6 +1454,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.90", +] + [[package]] name = "subtle" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index e787b059..b439a058 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = ["buildpacks/ruby", "commons"] [workspace.package] edition = "2021" -rust-version = "1.80" +rust-version = "1.82" [workspace.lints.rust] unreachable_pub = "warn" diff --git a/buildpacks/ruby/Cargo.toml b/buildpacks/ruby/Cargo.toml index 86953fa5..bb2739e5 100644 --- a/buildpacks/ruby/Cargo.toml +++ b/buildpacks/ruby/Cargo.toml @@ -30,6 +30,7 @@ ureq = { version = "2", default-features = false, features = ["tls"] } url = "2" magic_migrate = "0.2" toml = "0.8" +cache_diff = { version = "1.0.0", features = ["bullet_stream"] } [dev-dependencies] libcnb-test = "=0.26.1" diff --git a/buildpacks/ruby/src/layers/bundle_download_layer.rs b/buildpacks/ruby/src/layers/bundle_download_layer.rs index 59ad73db..3574549a 100644 --- a/buildpacks/ruby/src/layers/bundle_download_layer.rs +++ b/buildpacks/ruby/src/layers/bundle_download_layer.rs @@ -9,6 +9,7 @@ use crate::RubyBuildpack; use crate::RubyBuildpackError; use bullet_stream::state::SubBullet; use bullet_stream::{style, Print}; +use cache_diff::CacheDiff; use commons::gemfile_lock::ResolvedBundlerVersion; use fun_run::{self, CommandWithName}; use libcnb::data::layer_name; @@ -59,20 +60,13 @@ try_migrate_deserializer_chain!( impl MetadataDiff for Metadata { fn diff(&self, other: &Self) -> Vec { - let mut differences = Vec::new(); - if self.version != other.version { - differences.push(format!( - "Bundler version ({old} to {now})", - old = style::value(other.version.to_string()), - now = style::value(self.version.to_string()) - )); - } - differences + ::diff(self, other) } } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, CacheDiff)] pub(crate) struct MetadataV1 { + #[cache_diff(rename = "Bundler version")] pub(crate) version: ResolvedBundlerVersion, } @@ -141,12 +135,14 @@ mod test { let old = Metadata { version: ResolvedBundlerVersion("2.3.5".to_string()), }; - assert!(old.diff(&old).is_empty()); + assert!(CacheDiff::diff(&old, &old).is_empty()); - let diff = Metadata { - version: ResolvedBundlerVersion("2.3.6".to_string()), - } - .diff(&old); + let diff = CacheDiff::diff( + &Metadata { + version: ResolvedBundlerVersion("2.3.6".to_string()), + }, + &old, + ); assert_eq!( diff.iter().map(strip_ansi).collect::>(), vec!["Bundler version (`2.3.5` to `2.3.6`)"] diff --git a/buildpacks/ruby/src/layers/bundle_install_layer.rs b/buildpacks/ruby/src/layers/bundle_install_layer.rs index 989482ba..ed90f7ec 100644 --- a/buildpacks/ruby/src/layers/bundle_install_layer.rs +++ b/buildpacks/ruby/src/layers/bundle_install_layer.rs @@ -118,7 +118,7 @@ pub(crate) fn handle( pub(crate) type Metadata = MetadataV2; try_migrate_deserializer_chain!( - chain: [MetadataV1, MetadataV2], + chain: [MetadataV1, MetadataV2, MetadataV3], error: MetadataMigrateError, deserializer: toml::Deserializer::new, ); @@ -176,6 +176,15 @@ pub(crate) struct MetadataV2 { pub(crate) cpu_architecture: String, pub(crate) ruby_version: ResolvedRubyVersion, pub(crate) force_bundle_install_key: String, + pub(crate) digest: MetadataDigest, // Must be last for serde to be happy https://github.com/toml-rs/toml-rs/issues/142 +} + +#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] +pub(crate) struct MetadataV3 { + pub(crate) os_distribution: String, + pub(crate) cpu_architecture: String, + pub(crate) ruby_version: ResolvedRubyVersion, + pub(crate) force_bundle_install_key: String, /// A struct that holds the cryptographic hash of components that can /// affect the result of `bundle install`. When these values do not @@ -217,6 +226,20 @@ impl TryFrom for MetadataV2 { } } +impl TryFrom for MetadataV3 { + type Error = Infallible; + + fn try_from(v2: MetadataV2) -> Result { + Ok(Self { + os_distribution: format!("{} {}", v2.distro_name, v2.distro_version), + cpu_architecture: v2.cpu_architecture, + ruby_version: v2.ruby_version, + force_bundle_install_key: v2.force_bundle_install_key, + digest: v2.digest, + }) + } +} + #[derive(Debug)] enum InstallState { /// Holds message indicating the reason why we want to run 'bundle install'