Support Content Addressable File Naming - Gem Build Flow - #170
Conversation
…by_abi from required_ruby_version
f8e754f to
56b9bd9
Compare
…sable or standard)
b7ed231 to
f69c971
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends the gem build flow to optionally produce content-addressable gem filenames for platform gems that are scoped to a single Ruby ABI (via a new --ruby-abi flag). It introduces Ruby ABI derivation from required_ruby_version, validates/sets ABI requirements during build, and updates build output/packaging behavior accordingly.
Changes:
- Add
Gem::Specification#content_addressable_ruby_abito derive anX.YRuby ABI from a single pessimisticrequired_ruby_version. - Extend
Gem::Package.buildwith an optionalruby_abiargument to produce a digest-derived filename and validate/applyrequired_ruby_version. - Add/adjust tests and CLI help/options for the new build mode, and ensure
PackageTaskmoves whatever filenameGem::Package.buildreturns.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/rubygems/test_gem_specification.rb | Adds coverage for deriving a Ruby ABI from required_ruby_version. |
| test/rubygems/test_gem_package.rb | Adds coverage for content-addressable build naming and ruby ABI validation/error cases. |
| test/rubygems/test_gem_package_task.rb | Ensures packaging moves the filename returned by Gem::Package.build. |
| test/rubygems/test_gem_commands_build_command.rb | Adds CLI coverage for --ruby-abi and default option behavior. |
| lib/rubygems/specification.rb | Implements content_addressable_ruby_abi helper. |
| lib/rubygems/package.rb | Implements content-addressable build path, ruby ABI validation/application, and adjusts build output printing. |
| lib/rubygems/package_task.rb | Uses the actual built gem filename when moving artifacts to pkg/. |
| lib/rubygems/commands/build_command.rb | Adds the --ruby-abi option and help text; passes it through to Gem::Package.build. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| bytes = io.string | ||
| gem_file = "#{spec.name}-#{spec.version}-#{Digest::SHA256.hexdigest(bytes)[0, 10]}.gem" | ||
| File.binwrite(gem_file, bytes) | ||
| package.say " File: #{gem_file}" |
There was a problem hiding this comment.
A good point here. The requirement in the issue is "The gem is built in memory" so it would depend how tightly we're tied to that decision.
If open to an alternative, I think the next steps are probably to benchmark the largest platformed gem we have on RG.o and see what the build time would be for a Tempfile vs io.string to see what we would be gaining as a tradeoff for the extra complexity around a Tempfile.
… the --ruby_abi flag to gem build
f69c971 to
337170b
Compare
TL;DR
As part of the work to speed up
bundle install, this PR adjustsgem buildto support using content-addressable naming at build-time for a gem which only supports a single Ruby ABI.Summary
This PR introduces changes to the
gem buildprocess to assign a content-addressable file name during the build of a gem that only supports one Ruby ABI (a skinny gem).The bulk of the changes are in
Gem::Package. Inself.build, we now check if theruby_abiflag has been set when thegem buildcommand is run. Only if it has do we first validate the Ruby ABI value (and compare this to therequired_ruby_versionfor compatibility etc.) and then build a content addressable file if the validation passes without raising. If the user has passed a file name value at time of runninggem build, we raise, as we would not expect a content addressable gem to have a custom file name (it instead has a SHA value based on the file contents). As part of the CA file name compilation, we build the gem first in memory (usingStringIO.new), generate the SHA value from the file contents, and then write the file including the SHA value as the filename.There is also a minor change to
package_taskwhich ensures that we are eventually transferring the correct file output of the build (as now the name could take three different forms - standard, platformed or content addressed), and a helper method inspecification.rbwhich helps compare the Ruby ABI to therequired_ruby_versionprovided.Testing
Tests written in
test_gem_commands_build_command,test_gem_package,test_gem_package_task, andtest_gem_specificationto cover new behaviour.Tophat
Within IRB terminal, paste this script so you can see the output of using the
Gem::Package.buildcommand in different scenarios:To try the
gem buildcommand locally against this branch, you can run it through the RubyGems checkout rather than your installed RubyGems. From a test gem directory with a platformed gemspec, use:ruby --disable-gems -I/path/to/rubygems/lib /path/to/rubygems/exe/gem build *.gemspec --ruby-abi 3.4.As an example, for my checkout that is:ruby --disable-gems -I/Users/harrietoughton/rubygems/lib /Users/harrietoughton/rubygems/exe/gem build *.gemspec --ruby-abi 3.4.The single Ruby ABI built file should be named
<name>-<version>-<sha10>.gemrather than<name>-<version>-<platform>.gem.It's also worth testing out that you receive the expected behaviour with a wrong format ruby ABI (e.g.--ruby-abi 3), with a mismatched Ruby ABI andrequired_ruby_versionand when a gem is platformed with no Ruby ABI and when it is neither platformed nor intended for a single ABI.