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..633baebdd558a9 100644 --- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt @@ -1,132 +1,10 @@ -# Contributor Covenant Code of Conduct +# Code of Conduct -## Our Pledge +<%= 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.): -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. +* 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. -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 +If you have any concerns about behaviour within this project, please contact us at [<%= config[:email].inspect %>](mailto:<%= config[:email].inspect %>). 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..8fcece5d5ce252 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -393,16 +393,18 @@ 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], force: options[:force], - install_as_default: true, 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 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 0d0f0dc211ef1c..2d80e997879715 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -158,10 +158,9 @@ 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 end add_option(:"Install/Update", "--explain", diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 0cfe59b5bb5be3..52a352162e89c0 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 @@ -409,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 ## @@ -889,11 +884,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/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) 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 diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index b797960ac936a0..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 @@ -811,8 +849,8 @@ def install_specs(*specs) def install_default_gems(*specs) specs.each do |spec| - installer = Gem::Installer.for_spec(spec, install_as_default: true) - installer.install + installer = Gem::Installer.for_spec(spec) + installer.install_default_gem Gem.register_default_spec(spec) end 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" 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. 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