From d82a590a58c1a3898b997b9db939e7747a65a409 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Tue, 28 Oct 2025 00:24:17 -0700 Subject: [PATCH 01/11] sync_default_gems.rb: Show `git diff` on failed sync --- tool/sync_default_gems.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 55e8492851d363..3cba7010df3c80 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -626,8 +626,9 @@ def pickup_commit(gem, sha, edit) # If the cherry-pick attempt failed, try to resolve conflicts. # Skip the commit, if it contains unresolved conflicts or no files to pick up. unless picked or resolve_conflicts(gem, sha, edit) - `git reset` && `git checkout .` && `git clean -fd` - return picked || nil # Fail unless cherry-picked + system(*%w"git --no-pager diff") if !picked && !edit # If failed, show `git diff` unless editing + `git reset` && `git checkout .` && `git clean -fd` # Clean up un-committed diffs + return picked || nil # Fail unless cherry-picked end # Commit cherry-picked commit From aab390aa5ac863a74f867fec93eebab087f11060 Mon Sep 17 00:00:00 2001 From: Scott Myron Date: Tue, 28 Oct 2025 08:37:32 +0100 Subject: [PATCH 02/11] [ruby/json] Use Vector API in the Java Extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overview This PR uses the [jdk.incubator.vector module](https://docs.oracle.com/en/java/javase/20/docs/api/jdk.incubator.vector/jdk/incubator/vector/package-summary.html) as mentioned in [issue #739](https://github.com/ruby/json/issues/739) to accelerate generating JSON with the same algorithm as the C extension. The PR as it exists right now, it will attempt to build the `json.ext.VectorizedEscapeScanner` class with a target release of `16`. This is the first version of Java with support for the `jdk.incubator.vector` module. The remaining code is built for Java 1.8. The code will attempt to load the `json.ext.VectorizedEscapeScanner` only if the `json.enableVectorizedEscapeScanner` system property is set to `true` (or `1`). I'm not entirely sure how this is packaged / included with JRuby so I'd love @byroot and @headius's (and others?) thought about how to potential package and/or structure the JARs. I did consider adding the `json.ext.VectorizedEscapeScanner` to a separate `generator-vectorized.jar` but I thought I'd solicit feedback before spending any more time on the build / package process. Benchmarks Machine M1 Macbook Air Note: I've had trouble modifying the `compare.rb` I was using for the C extension to work reliability with the Java extension. I'll probably spend more time trying to get it to work, but as of right now these are pretty raw benchmarks. Below are two sample runs of the real-world benchmarks. The benchmarks are much more variable then the C extension for some reason. I'm not sure if HotSpot is doing something slightly different per execution. Vector API Enabled ``` scott@Scotts-MacBook-Air json % ONLY=json JAVA_OPTS='--add-modules jdk.incubator.vector -Djson.enableVectorizedEscapeScanner=true' ruby -I"lib" benchmark/encoder-realworld.rb WARNING: Using incubator modules: jdk.incubator.vector == Encoding activitypub.json (52595 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 1.384k i/100ms Calculating ------------------------------------- json 15.289k (± 0.8%) i/s (65.41 μs/i) - 153.624k in 10.048481s == Encoding citm_catalog.json (500298 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 76.000 i/100ms Calculating ------------------------------------- json 753.787 (± 3.6%) i/s (1.33 ms/i) - 7.524k in 9.997059s == Encoding twitter.json (466906 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 173.000 i/100ms Calculating ------------------------------------- json 1.751k (± 1.1%) i/s (571.24 μs/i) - 17.646k in 10.081260s == Encoding ohai.json (20147 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 2.390k i/100ms Calculating ------------------------------------- json 23.829k (± 0.8%) i/s (41.97 μs/i) - 239.000k in 10.030503s ``` Vector API Disabled ``` scott@Scotts-MacBook-Air json % ONLY=json JAVA_OPTS='--add-modules jdk.incubator.vector -Djson.enableVectorizedEscapeScanner=false' ruby -I"lib" benchmark/encoder-realworld.rb WARNING: Using incubator modules: jdk.incubator.vector VectorizedEscapeScanner disabled. == Encoding activitypub.json (52595 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 1.204k i/100ms Calculating ------------------------------------- json 12.937k (± 1.1%) i/s (77.30 μs/i) - 130.032k in 10.052234s == Encoding citm_catalog.json (500298 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 80.000 i/100ms Calculating ------------------------------------- json 817.378 (± 1.0%) i/s (1.22 ms/i) - 8.240k in 10.082058s == Encoding twitter.json (466906 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 147.000 i/100ms Calculating ------------------------------------- json 1.499k (± 1.3%) i/s (667.08 μs/i) - 14.994k in 10.004181s == Encoding ohai.json (20147 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 2.269k i/100ms Calculating ------------------------------------- json 22.366k (± 5.7%) i/s (44.71 μs/i) - 224.631k in 10.097069s ``` `master` as of commit `https://github.com/ruby/json/commit/c5af1b68c582` ``` scott@Scotts-MacBook-Air json % ONLY=json ruby -I"lib" benchmark/encoder-realworld.rb == Encoding activitypub.json (52595 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 886.000 i/100ms Calculating ------------------------------------- json^C% scott@Scotts-MacBook-Air json % ONLY=json ruby -I"lib" benchmark/encoder-realworld.rb == Encoding activitypub.json (52595 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 1.031k i/100ms Calculating ------------------------------------- json 10.812k (± 1.3%) i/s (92.49 μs/i) - 108.255k in 10.014260s == Encoding citm_catalog.json (500298 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 82.000 i/100ms Calculating ------------------------------------- json 824.921 (± 1.0%) i/s (1.21 ms/i) - 8.282k in 10.040787s == Encoding twitter.json (466906 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 141.000 i/100ms Calculating ------------------------------------- json 1.421k (± 0.7%) i/s (703.85 μs/i) - 14.241k in 10.023979s == Encoding ohai.json (20147 bytes) jruby 9.4.12.0 (3.1.4) 2025-02-11 https://github.com/ruby/json/commit/f4ab75096a Java HotSpot(TM) 64-Bit Server VM 21.0.7+8-LTS-245 on 21.0.7+8-LTS-245 +jit [arm64-darwin] Warming up -------------------------------------- json 2.274k i/100ms Calculating ------------------------------------- json 22.612k (± 0.9%) i/s (44.22 μs/i) - 227.400k in 10.057516s ``` Observations `activitypub.json` and `twitter.json` seem to be consistently faster with the Vector API enabled. `citm_catalog.json` seems consistently a bit slower and `ohai.json` is fairly close to even. https://github.com/ruby/json/commit/d40b2703a8 --- test/json/json_encoding_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/json/json_encoding_test.rb b/test/json/json_encoding_test.rb index 2789e94b5b3f2b..7ac06b2a7b0093 100644 --- a/test/json/json_encoding_test.rb +++ b/test/json/json_encoding_test.rb @@ -37,6 +37,10 @@ def test_generate_shared_string assert_equal '"234567890"', JSON.dump(s[2..-1]) s = '01234567890123456789"a"b"c"d"e"f"g"h' assert_equal '"\"a\"b\"c\"d\"e\"f\"g\""', JSON.dump(s[20, 15]) + s = "0123456789001234567890012345678900123456789001234567890" + assert_equal '"23456789001234567890012345678900123456789001234567890"', JSON.dump(s[2..-1]) + s = "0123456789001234567890012345678900123456789001234567890" + assert_equal '"567890012345678900123456789001234567890012345678"', JSON.dump(s[5..-3]) end def test_unicode From 7550f7e453713b776cf39d9ccd0154d9e33cf6f1 Mon Sep 17 00:00:00 2001 From: dysonreturns <22199434-dysonreturns@users.noreply.gitlab.com> Date: Tue, 21 Oct 2025 11:21:09 -0700 Subject: [PATCH 03/11] [ruby/rubygems] Update new gem CoC and prompt Prompt wording "prefer safe, respectful, productive, and collaborative spaces" is copied verbatim from Ruby Community Conduct Guideline. https://github.com/ruby/rubygems/commit/6cdf5f6d8a --- lib/bundler/cli/gem.rb | 8 +- .../templates/newgem/CODE_OF_CONDUCT.md.tt | 138 ++---------------- 2 files changed, 11 insertions(+), 135 deletions(-) diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 56d23d9e9fc293..23b29bf36bee36 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -178,12 +178,8 @@ def run if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", "Codes of conduct can increase contributions to your project by contributors who " \ - "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ - "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ - "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ - "address is specified as a contact in the generated code of conduct so that people know " \ - "who to contact in case of a violation. For suggestions about " \ - "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.") + "prefer safe, respectful, productive, and collaborative spaces. \n" \ + "See https://github.com/ruby/rubygems/blob/master/CODE_OF_CONDUCT.md") config[:coc] = true Bundler.ui.info "Code of conduct enabled in config" templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt index 67fe8cee798a7d..29e43a688ad049 100644 --- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt @@ -1,132 +1,12 @@ -# Contributor Covenant Code of Conduct +# Code of Conduct -## Our Pledge +These practices were derived from the Ruby Community Conduct Guideline. -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. +This document provides community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to the project. +It applies to all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). +Other communities may pick their own Code of Conduct. -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official email address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -[INSERT CONTACT METHOD]. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. - -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at -[https://www.contributor-covenant.org/translations][translations]. - -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[Mozilla CoC]: https://github.com/mozilla/diversity -[FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations +* Participants will be tolerant of opposing views. +* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. +* When interpreting the words and actions of others, participants should always assume good intentions. +* Behaviour which can be reasonably considered harassment will not be tolerated. From a27f430de7fdf9b4ab9b158c44aa40b81bd705cd Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 23 Oct 2025 09:08:33 +0900 Subject: [PATCH 04/11] [ruby/rubygems] Make more shortly with https://rubyonrails.org/conduct https://github.com/ruby/rubygems/commit/62ba34d6c9 --- lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt index 29e43a688ad049..633baebdd558a9 100644 --- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt @@ -1,12 +1,10 @@ # Code of Conduct -These practices were derived from the Ruby Community Conduct Guideline. - -This document provides community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to the project. -It applies to all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). -Other communities may pick their own Code of Conduct. +<%= config[:name].inspect %> follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.): * Participants will be tolerant of opposing views. * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. * When interpreting the words and actions of others, participants should always assume good intentions. * Behaviour which can be reasonably considered harassment will not be tolerated. + +If you have any concerns about behaviour within this project, please contact us at [<%= config[:email].inspect %>](mailto:<%= config[:email].inspect %>). From 523474bdfcae518ff74d2455f5199ea1df0af760 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 15:28:50 +0900 Subject: [PATCH 05/11] [ruby/rubygems] Deprecate --default option https://github.com/ruby/rubygems/commit/55745ee0f8 --- lib/rubygems/install_update_options.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index 0d0f0dc211ef1c..57c41b75861c1c 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -158,7 +158,7 @@ def add_install_update_options options[:without_groups].concat v.map(&:intern) end - add_option(:"Install/Update", "--default", + add_option(:Deprecated, "--default", "Add the gem's full specification to", "specifications/default and extract only its bin") do |v,_o| options[:install_as_default] = v From d67aba8a5d81383880e05504de9a52ab6b2a015e Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 15:38:00 +0900 Subject: [PATCH 06/11] [ruby/rubygems] Completely removed install_as_default feature https://github.com/ruby/rubygems/commit/15e46a3a68 --- lib/rubygems/commands/install_command.rb | 6 +- lib/rubygems/commands/setup_command.rb | 1 - lib/rubygems/dependency_installer.rb | 3 - lib/rubygems/install_default_message.rb | 13 --- lib/rubygems/install_update_options.rb | 1 - lib/rubygems/installer.rb | 31 ++----- test/rubygems/helper.rb | 2 +- test/rubygems/test_gem_installer.rb | 113 ----------------------- 8 files changed, 10 insertions(+), 160 deletions(-) delete mode 100644 lib/rubygems/install_default_message.rb diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index 2888b6c55a8372..70d32013ba6ad0 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -239,11 +239,7 @@ def install_gems # :nodoc: # Loads post-install hooks def load_hooks # :nodoc: - if options[:install_as_default] - require_relative "../install_default_message" - else - require_relative "../install_message" - end + require_relative "../install_message" require_relative "../rdoc" end diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index 85e28cceddf608..2b9c522a6b6a21 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -398,7 +398,6 @@ def install_default_bundler_gem(bin_dir) env_shebang: options[:env_shebang], format_executable: options[:format_executable], force: options[:force], - install_as_default: true, bin_dir: bin_dir, install_dir: default_dir, wrappers: true diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index b4152e83e913b4..6fbfe53643a2ae 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -28,7 +28,6 @@ class Gem::DependencyInstaller wrappers: true, build_args: nil, build_docs_in_background: false, - install_as_default: false, }.freeze ## @@ -87,7 +86,6 @@ def initialize(options = {}) @wrappers = options[:wrappers] @build_args = options[:build_args] @build_docs_in_background = options[:build_docs_in_background] - @install_as_default = options[:install_as_default] @dir_mode = options[:dir_mode] @data_mode = options[:data_mode] @prog_mode = options[:prog_mode] @@ -240,7 +238,6 @@ def install(dep_or_name, version = Gem::Requirement.default) user_install: @user_install, wrappers: @wrappers, build_root: @build_root, - install_as_default: @install_as_default, dir_mode: @dir_mode, data_mode: @data_mode, prog_mode: @prog_mode, diff --git a/lib/rubygems/install_default_message.rb b/lib/rubygems/install_default_message.rb deleted file mode 100644 index 0640eaaf08832e..00000000000000 --- a/lib/rubygems/install_default_message.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require_relative "../rubygems" -require_relative "user_interaction" - -## -# A post-install hook that displays "Successfully installed -# some_gem-1.0 as a default gem" - -Gem.post_install do |installer| - ui = Gem::DefaultUserInteraction.ui - ui.say "Successfully installed #{installer.spec.full_name} as a default gem" -end diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index 57c41b75861c1c..2d80e997879715 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -161,7 +161,6 @@ def add_install_update_options add_option(:Deprecated, "--default", "Add the gem's full specification to", "specifications/default and extract only its bin") do |v,_o| - options[:install_as_default] = v end add_option(:"Install/Update", "--explain", diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 0cfe59b5bb5be3..46c4844ab96188 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -274,11 +274,7 @@ def install run_pre_install_hooks # Set loaded_from to ensure extension_dir is correct - if @options[:install_as_default] - spec.loaded_from = default_spec_file - else - spec.loaded_from = spec_file - end + spec.loaded_from = spec_file # Completely remove any previous gem files FileUtils.rm_rf gem_dir @@ -287,24 +283,17 @@ def install dir_mode = options[:dir_mode] FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755 - if @options[:install_as_default] - extract_bin - write_default_spec - else - extract_files + extract_files - build_extensions - write_build_info_file - run_post_build_hooks - end + build_extensions + write_build_info_file + run_post_build_hooks generate_bin generate_plugins - unless @options[:install_as_default] - write_spec - write_cache_file - end + write_spec + write_cache_file File.chmod(dir_mode, gem_dir) if dir_mode @@ -889,11 +878,7 @@ def pre_install_checks ensure_loadable_spec - if options[:install_as_default] - Gem.ensure_default_gem_subdirectories gem_home - else - Gem.ensure_gem_subdirectories gem_home - end + Gem.ensure_gem_subdirectories gem_home return true if @force diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index b797960ac936a0..ecd92b0a572e8e 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -811,7 +811,7 @@ def install_specs(*specs) def install_default_gems(*specs) specs.each do |spec| - installer = Gem::Installer.for_spec(spec, install_as_default: true) + installer = Gem::Installer.for_spec(spec) installer.install Gem.register_default_spec(spec) end diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 34415aa7dd7e1d..3fa617ef50e04a 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2425,119 +2425,6 @@ def test_dir assert_match %r{/gemhome/gems/a-2$}, installer.dir end - def test_default_gem_loaded_from - spec = util_spec "a" - installer = Gem::Installer.for_spec spec, install_as_default: true - installer.install - assert_predicate spec, :default_gem? - end - - def test_default_gem_without_wrappers - installer = setup_base_installer - - FileUtils.rm_rf File.join(Gem.default_dir, "specifications") - - installer.wrappers = false - installer.options[:install_as_default] = true - installer.gem_dir = @spec.gem_dir - - use_ui @ui do - installer.install - end - - assert_directory_exists File.join(@spec.gem_dir, "bin") - installed_exec = File.join @spec.gem_dir, "bin", "executable" - assert_path_exist installed_exec - - assert_directory_exists File.join(Gem.default_dir, "specifications") - assert_directory_exists File.join(Gem.default_dir, "specifications", "default") - - default_spec = eval File.read File.join(Gem.default_dir, "specifications", "default", "a-2.gemspec") - assert_equal Gem::Version.new("2"), default_spec.version - assert_equal ["bin/executable"], default_spec.files - - assert_directory_exists util_inst_bindir - - installed_exec = File.join util_inst_bindir, "executable" - assert_path_exist installed_exec - - wrapper = File.read installed_exec - - if symlink_supported? - refute_match(/generated by RubyGems/, wrapper) - else # when symlink not supported, it warns and fallbacks back to installing wrapper - assert_match(/Unable to use symlinks, installing wrapper/, @ui.error) - assert_match(/generated by RubyGems/, wrapper) - end - end - - def test_default_gem_with_wrappers - installer = setup_base_installer - - installer.wrappers = true - installer.options[:install_as_default] = true - installer.gem_dir = @spec.gem_dir - - use_ui @ui do - installer.install - end - - assert_directory_exists util_inst_bindir - - installed_exec = File.join util_inst_bindir, "executable" - assert_path_exist installed_exec - - wrapper = File.read installed_exec - assert_match(/generated by RubyGems/, wrapper) - end - - def test_default_gem_with_exe_as_bindir - @spec = quick_gem "c" do |spec| - util_make_exec spec, "#!/usr/bin/ruby", "exe" - end - - util_build_gem @spec - - @spec.cache_file - - installer = util_installer @spec, @gemhome - - installer.options[:install_as_default] = true - installer.gem_dir = @spec.gem_dir - - use_ui @ui do - installer.install - end - - assert_directory_exists File.join(@spec.gem_dir, "exe") - installed_exec = File.join @spec.gem_dir, "exe", "executable" - assert_path_exist installed_exec - - assert_directory_exists File.join(Gem.default_dir, "specifications") - assert_directory_exists File.join(Gem.default_dir, "specifications", "default") - - default_spec = eval File.read File.join(Gem.default_dir, "specifications", "default", "c-2.gemspec") - assert_equal Gem::Version.new("2"), default_spec.version - assert_equal ["exe/executable"], default_spec.files - end - - def test_default_gem_to_specific_install_dir - @gem = setup_base_gem - installer = util_installer @spec, "#{@gemhome}2" - installer.options[:install_as_default] = true - - use_ui @ui do - installer.install - end - - assert_directory_exists File.join("#{@gemhome}2", "specifications") - assert_directory_exists File.join("#{@gemhome}2", "specifications", "default") - - default_spec = eval File.read File.join("#{@gemhome}2", "specifications", "default", "a-2.gemspec") - assert_equal Gem::Version.new("2"), default_spec.version - assert_equal ["bin/executable"], default_spec.files - end - def test_package_attribute gem = quick_gem "c" do |spec| util_make_exec spec, "#!/usr/bin/ruby", "exe" From ceb2b569af29ae515042c5fbab533e003ac42a4d Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 15:59:19 +0900 Subject: [PATCH 07/11] [ruby/rubygems] Added install_default_gem method for testing https://github.com/ruby/rubygems/commit/81dbd42abf --- test/rubygems/helper.rb | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index ecd92b0a572e8e..53bed0b4151b97 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -60,6 +60,44 @@ def self.specific_extra_args_hash=(value) end end +class Gem::Installer + # Copy from Gem::Installer#install with install_as_default option from old version + def install_default_gem + pre_install_checks + + run_pre_install_hooks + + spec.loaded_from = default_spec_file + + FileUtils.rm_rf gem_dir + FileUtils.rm_rf spec.extension_dir + + dir_mode = options[:dir_mode] + FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755 + + extract_bin + write_default_spec + + generate_bin + generate_plugins + + File.chmod(dir_mode, gem_dir) if dir_mode + + say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil? + + Gem::Specification.add_spec(spec) + + load_plugin + + run_post_install_hooks + + spec + rescue Errno::EACCES => e + # Permission denied - /path/to/foo + raise Gem::FilePermissionError, e.message.split(" - ").last + end +end + ## # RubyGemTestCase provides a variety of methods for testing rubygems and # gem-related behavior in a sandbox. Through RubyGemTestCase you can install @@ -812,7 +850,7 @@ def install_specs(*specs) def install_default_gems(*specs) specs.each do |spec| installer = Gem::Installer.for_spec(spec) - installer.install + installer.install_default_gem Gem.register_default_spec(spec) end end From 7bd7bcbf3e683e3d4d88696b72444e6c14685cc2 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 16:29:10 +0900 Subject: [PATCH 08/11] [ruby/rubygems] Removed default bundler spec from specification directory https://github.com/ruby/rubygems/commit/6fbbde48e2 --- lib/rubygems/commands/setup_command.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index 2b9c522a6b6a21..8fcece5d5ce252 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -393,7 +393,7 @@ def install_default_bundler_gem(bin_dir) Dir.chdir("bundler") do built_gem = Gem::Package.build(new_bundler_spec) begin - Gem::Installer.at( + installer = Gem::Installer.at( built_gem, env_shebang: options[:env_shebang], format_executable: options[:format_executable], @@ -401,7 +401,10 @@ def install_default_bundler_gem(bin_dir) bin_dir: bin_dir, install_dir: default_dir, wrappers: true - ).install + ) + installer.install + File.delete installer.spec_file + installer.write_default_spec ensure FileUtils.rm_f built_gem end From 3afe8ed46f3cf71ae48703c5264d2d0712597a59 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 17:40:29 +0900 Subject: [PATCH 09/11] [ruby/rubygems] Introduce default_spec_dir when it's not provided https://github.com/ruby/rubygems/commit/e9bd59699c --- lib/rubygems/installer.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 46c4844ab96188..52a352162e89c0 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -398,12 +398,18 @@ def spec_file File.join gem_home, "specifications", "#{spec.full_name}.gemspec" end + def default_spec_dir + dir = File.join(gem_home, "specifications", "default") + FileUtils.mkdir_p dir + dir + end + ## # The location of the default spec file for default gems. # def default_spec_file - File.join gem_home, "specifications", "default", "#{spec.full_name}.gemspec" + File.join default_spec_dir, "#{spec.full_name}.gemspec" end ## From 52451798d2647739912b8a32b055ff998abe69a7 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 18 Apr 2024 17:40:49 +0900 Subject: [PATCH 10/11] [ruby/rubygems] Simulate default gems manually https://github.com/ruby/rubygems/commit/c3cc38c72c --- spec/bundler/support/helpers.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index 17c38c77607d4f..719a6e65d2626c 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -333,9 +333,20 @@ def install_gem(path, install_dir, default = false) raise "OMG `#{path}` does not exist!" unless File.exist?(path) args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}" - args += " --default" if default gem_command "install #{args} '#{path}'" + + if default + gem = Pathname.new(path).basename.to_s.match(/(.*)\.gem/)[1] + + # Revert Gem::Installer#write_spec and apply Gem::Installer#write_default_spec + FileUtils.mkdir_p File.join(install_dir, "specifications", "default") + File.rename File.join(install_dir, "specifications", gem + ".gemspec"), + File.join(install_dir, "specifications", "default", gem + ".gemspec") + + # Revert Gem::Installer#write_cache_file + File.delete File.join(install_dir, "cache", gem + ".gem") + end end def with_built_bundler(version = nil, opts = {}, &block) From b0825d78f3e42565af47a53d93713c7e1dd7a04d Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 28 Oct 2025 20:27:53 +0900 Subject: [PATCH 11/11] Restore old version of Gem::Installer#install for default gems installation --- tool/rbinstall.rb | 73 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/tool/rbinstall.rb b/tool/rbinstall.rb index df15c65b54b11a..936ef8242d7ecb 100755 --- a/tool/rbinstall.rb +++ b/tool/rbinstall.rb @@ -709,6 +709,77 @@ def extract_files(destination_dir, pattern = "*") end class UnpackedInstaller < Gem::Installer + # This method is mostly copied from old version of Gem::Installer#install + def install_with_default_gem + verify_gem_home + + # The name and require_paths must be verified first, since it could contain + # ruby code that would be eval'ed in #ensure_loadable_spec + verify_spec + + ensure_loadable_spec + + if options[:install_as_default] + Gem.ensure_default_gem_subdirectories gem_home + else + Gem.ensure_gem_subdirectories gem_home + end + + return true if @force + + ensure_dependencies_met unless @ignore_dependencies + + run_pre_install_hooks + + # Set loaded_from to ensure extension_dir is correct + if @options[:install_as_default] + spec.loaded_from = default_spec_file + else + spec.loaded_from = spec_file + end + + # Completely remove any previous gem files + FileUtils.rm_rf gem_dir + FileUtils.rm_rf spec.extension_dir + + dir_mode = options[:dir_mode] + FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755 + + if @options[:install_as_default] + extract_bin + write_default_spec + else + extract_files + + build_extensions + write_build_info_file + run_post_build_hooks + end + + generate_bin + generate_plugins + + unless @options[:install_as_default] + write_spec + write_cache_file + end + + File.chmod(dir_mode, gem_dir) if dir_mode + + say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil? + + Gem::Specification.add_spec(spec) unless @install_dir + + load_plugin + + run_post_install_hooks + + spec + rescue Errno::EACCES => e + # Permission denied - /path/to/foo + raise Gem::FilePermissionError, e.message.split(" - ").last + end + def write_cache_file end @@ -754,7 +825,7 @@ def write_default_spec def install spec.post_install_message = nil dir_creating(without_destdir(gem_dir)) - RbInstall.no_write(options) {super} + RbInstall.no_write(options) { install_with_default_gem } end # Now build-ext builds all extensions including bundled gems.