diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-03-08 12:17:52 +0900 |
---|---|---|
committer | NARUSE, Yui <nurse@users.noreply.github.com> | 2021-03-11 17:24:52 +0900 |
commit | 7efc7afcae6720e1af7ab49986d789b6f9d6fe0a (patch) | |
tree | cfc13bbb77911924b689147c74947ec0850eded1 | |
parent | 06cd5711e0afc6302052e847863a7fdcc42fe692 (diff) |
Merge RubyGems-3.2.13 and Bundler-2.2.13
24 files changed, 477 insertions, 267 deletions
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 0d773579e5..2c63da9eb4 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -39,11 +39,11 @@ module Bundler constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } constant_array = constant_name.split("::") - git_installed = Bundler.git_present? + use_git = Bundler.git_present? && options[:git] - git_author_name = git_installed ? `git config user.name`.chomp : "" - github_username = git_installed ? `git config github.user`.chomp : "" - git_user_email = git_installed ? `git config user.email`.chomp : "" + git_author_name = use_git ? `git config user.name`.chomp : "" + github_username = use_git ? `git config github.user`.chomp : "" + git_user_email = use_git ? `git config user.email`.chomp : "" config = { :name => name, @@ -58,6 +58,7 @@ module Bundler :ext => options[:ext], :exe => options[:exe], :bundler_version => bundler_dependency_version, + :git => use_git, :github_username => github_username.empty? ? "[USERNAME]" : github_username, :required_ruby_version => Gem.ruby_version < Gem::Version.new("2.4.a") ? "2.3.0" : "2.4.0", } @@ -79,7 +80,7 @@ module Bundler bin/setup ] - templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present? + templates.merge!("gitignore.tt" => ".gitignore") if use_git if test_framework = ask_and_set_test_framework config[:test] = test_framework @@ -175,24 +176,31 @@ module Bundler ) end + if File.exist?(target) && !File.directory?(target) + Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." + exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] + end + + if use_git + Bundler.ui.info "Initializing git repo in #{target}" + `git init #{target}` + + config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp + end + templates.each do |src, dst| destination = target.join(dst) - SharedHelpers.filesystem_access(destination) do - thor.template("newgem/#{src}", destination, config) - end + thor.template("newgem/#{src}", destination, config) end executables.each do |file| - SharedHelpers.filesystem_access(target.join(file)) do |path| - executable = (path.stat.mode | 0o111) - path.chmod(executable) - end + path = target.join(file) + executable = (path.stat.mode | 0o111) + path.chmod(executable) end - if Bundler.git_present? && options[:git] - Bundler.ui.info "Initializing git repo in #{target}" + if use_git Dir.chdir(target) do - `git init` `git add .` end end @@ -202,8 +210,6 @@ module Bundler Bundler.ui.info "Gem '#{name}' was successfully created. " \ "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" - rescue Errno::EEXIST => e - raise GenericSystemCallError.new(e, "There was a conflict while creating the new gem.") end private diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 3264cb074c..a09d661a07 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -264,7 +264,7 @@ module Bundler # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) - Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end end end @@ -656,19 +656,20 @@ module Bundler def converge_rubygems_sources return false if Bundler.feature_flag.disable_multisource? - changes = false - # Get the RubyGems sources from the Gemfile.lock locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } + return false if locked_gem_sources.empty? + # Get the RubyGems remotes from the Gemfile actual_remotes = sources.rubygems_remotes + return false if actual_remotes.empty? + + changes = false # If there is a RubyGems source in both - if !locked_gem_sources.empty? && !actual_remotes.empty? - locked_gem_sources.each do |locked_gem| - # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) - end + locked_gem_sources.each do |locked_gem| + # Merge the remotes from the Gemfile into the Gemfile.lock + changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) end changes @@ -893,30 +894,18 @@ module Bundler # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) - default = sources.default_source - source_requirements = { :default => default } - default = nil unless Bundler.feature_flag.disable_multisource? - dependencies.each do |dep| - next unless source = dep.source || default - source_requirements[dep.name] = source - end + source_requirements = { :default => sources.default_source }.merge(dependency_source_requirements) metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end + source_requirements[:global] = index unless Bundler.feature_flag.disable_multisource? source_requirements[:default_bundler] = source_requirements["bundler"] || source_requirements[:default] source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end def pinned_spec_names(skip = nil) - pinned_names = [] - default = Bundler.feature_flag.disable_multisource? && sources.default_source - @dependencies.each do |dep| - next unless dep_source = dep.source || default - next if dep_source == skip - pinned_names << dep.name - end - pinned_names + dependency_source_requirements.reject {|_, source| source == skip }.keys end def requested_groups @@ -973,5 +962,17 @@ module Bundler Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) end + + def dependency_source_requirements + @dependency_source_requirements ||= begin + source_requirements = {} + default = sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + source_requirements[dep.name] = dep_source + end + source_requirements + end + end end end diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 1cc7908b8a..23fba99ffa 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -24,6 +24,9 @@ module Bundler def initialize @source = nil @sources = SourceList.new + + @global_rubygems_sources = [] + @git_sources = {} @dependencies = [] @groups = [] @@ -45,6 +48,7 @@ module Bundler @gemfiles << expanded_gemfile_path contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) + check_primary_source_safety rescue Exception => e # rubocop:disable Lint/RescueException message = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ @@ -164,8 +168,7 @@ module Bundler elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else - check_primary_source_safety(@sources) - @sources.global_rubygems_source = source + @global_rubygems_sources << source end end @@ -183,24 +186,14 @@ module Bundler end def path(path, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a path source by itself. Instead, \n" \ - "either use the :path option on a gem, or specify the gems that \n" \ - "bundler should find in the path source by passing a block to \n" \ - "the path method, like: \n\n" \ - " path 'dir/containing/rails' do\n" \ - " gem 'rails'\n" \ - " end\n\n" - - raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? - SharedHelpers.major_deprecation(2, msg.strip) - end - source_options = normalize_hash(options).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, "gemspec" => gemspecs.find {|g| g.name == options["name"] } ) + + source_options["global"] = true unless block_given? + source = @sources.add_path_source(source_options) with_source(source, &blk) end @@ -279,6 +272,11 @@ module Bundler raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" end + def check_primary_source_safety + check_path_source_safety + check_rubygems_source_safety + end + private def add_git_sources @@ -440,17 +438,33 @@ repo_name ||= user_name end end - def check_primary_source_safety(source_list) - return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? + def check_path_source_safety + return if @sources.global_path_source.nil? + + msg = "You can no longer specify a path source by itself. Instead, \n" \ + "either use the :path option on a gem, or specify the gems that \n" \ + "bundler should find in the path source by passing a block to \n" \ + "the path method, like: \n\n" \ + " path 'dir/containing/rails' do\n" \ + " gem 'rails'\n" \ + " end\n\n" + + SharedHelpers.major_deprecation(2, msg.strip) + end + + def check_rubygems_source_safety + @sources.global_rubygems_source = @global_rubygems_sources.shift + return if @global_rubygems_sources.empty? + + @global_rubygems_sources.each do |source| + @sources.add_rubygems_remote(source) + end if Bundler.feature_flag.disable_multisource? msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ - "should come from that source" - unless Bundler.feature_flag.bundler_2_mode? - msg += ". To downgrade this error to a warning, run " \ - "`bundle config unset disable_multisource`" - end + "should come from that source. To downgrade this error to a warning, run " \ + "`bundle config unset disable_multisource`" raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index 59211193d4..02da06cee9 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -50,6 +50,7 @@ def gemfile(install = false, options = {}, &gemfile) Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? builder = Bundler::Dsl.new builder.instance_eval(&gemfile) + builder.check_primary_source_safety Bundler.settings.temporary(:frozen => false) do definition = builder.to_definition(nil, true) diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index f836737621..058d353bbe 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -64,8 +64,6 @@ module Bundler @state = nil @specs = {} - @rubygems_aggregate = Source::Rubygems.new - if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." @@ -89,7 +87,6 @@ module Bundler send("parse_#{@state}", line) end end - @sources << @rubygems_aggregate unless Bundler.feature_flag.disable_multisource? @specs = @specs.values.sort_by(&:identifier) warn_for_outdated_bundler_version rescue ArgumentError => e @@ -134,16 +131,19 @@ module Bundler @sources << @current_source end when GEM - if Bundler.feature_flag.disable_multisource? + source_remotes = Array(@opts["remote"]) + + if source_remotes.size == 1 @opts["remotes"] = @opts.delete("remote") @current_source = TYPES[@type].from_lock(@opts) - @sources << @current_source else - Array(@opts["remote"]).each do |url| - @rubygems_aggregate.add_remote(url) + source_remotes.each do |url| + rubygems_aggregate.add_remote(url) end - @current_source = @rubygems_aggregate + @current_source = rubygems_aggregate end + + @sources << @current_source when PLUGIN @current_source = Plugin.source_from_lock(@opts) @sources << @current_source @@ -245,5 +245,9 @@ module Bundler def parse_ruby(line) @ruby_version = line.strip end + + def rubygems_aggregate + @rubygems_aggregate ||= Source::Rubygems.new + end end end diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index da3f468da5..dddb468582 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -105,6 +105,7 @@ module Bundler else builder.eval_gemfile(gemfile) end + builder.check_primary_source_safety definition = builder.to_definition(nil, true) return if definition.dependencies.empty? diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 26cec4f18c..980b0e29b8 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -16,15 +16,13 @@ module Bundler version = options[:version] || [">= 0"] - Bundler.settings.temporary(:disable_multisource => false) do - if options[:git] - install_git(names, version, options) - elsif options[:local_git] - install_local_git(names, version, options) - else - sources = options[:source] || Bundler.rubygems.sources - install_rubygems(names, version, sources) - end + if options[:git] + install_git(names, version, options) + elsif options[:local_git] + install_local_git(names, version, options) + else + sources = options[:source] || Bundler.rubygems.sources + install_rubygems(names, version, sources) end end @@ -79,7 +77,7 @@ module Bundler source_list = SourceList.new source_list.add_git_source(git_source_options) if git_source_options - source_list.add_rubygems_source("remotes" => rubygems_source) if rubygems_source + source_list.global_rubygems_source = rubygems_source if rubygems_source deps = names.map {|name| Dependency.new name, version } diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb index b90a331d28..547661cf2f 100644 --- a/lib/bundler/plugin/source_list.rb +++ b/lib/bundler/plugin/source_list.rb @@ -17,6 +17,10 @@ module Bundler path_sources + git_sources + rubygems_sources + [metadata_source] end + def default_source + git_sources.first || global_rubygems_source + end + private def rubygems_aggregate_class diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 585b8667ad..69899dc6c3 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -17,16 +17,21 @@ module Bundler # ==== Returns # <GemBundle>,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. - def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) + def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) base = SpecSet.new(base) unless base.is_a?(SpecSet) - resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) + resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) SpecSet.new(result) end - def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) - @index = index + def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements + + @index_requirements = source_requirements.each_with_object({}) do |source_requirement, index_requirements| + name, source = source_requirement + index_requirements[name] = name == :global ? source : source.specs + end + @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @@ -40,7 +45,7 @@ module Bundler @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? - @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource? + @no_aggregate_global_source = @source_requirements[:global].nil? @variant_specific_names = [] @generic_names = ["Ruby\0", "RubyGems\0"] @@ -125,8 +130,7 @@ module Bundler dependency = dependency_proxy.dep name = dependency.name search_result = @search_for[dependency_proxy] ||= begin - index = index_for(dependency) - results = index.search(dependency, @base[name]) + results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) locked_requirement = vertex.payload.requirement @@ -196,22 +200,22 @@ module Bundler end def index_for(dependency) - source = @source_requirements[dependency.name] + source = @index_requirements[dependency.name] if source - source.specs - elsif @lockfile_uses_separate_rubygems_sources + source + elsif @no_aggregate_global_source Index.build do |idx| - if dependency.all_sources - dependency.all_sources.each {|s| idx.add_source(s.specs) if s } - else - idx.add_source @source_requirements[:default].specs - end + dependency.all_sources.each {|s| idx.add_source(s.specs) } end else - @index + @index_requirements[:global] end end + def results_for(dependency, base) + index_for(dependency).search(dependency, base) + end + def name_for(dependency) dependency.name end @@ -239,18 +243,20 @@ module Bundler def relevant_sources_for_vertex(vertex) if vertex.root? [@source_requirements[vertex.name]] - elsif @lockfile_uses_separate_rubygems_sources + elsif @no_aggregate_global_source vertex.recursive_predecessors.map do |v| @source_requirements[v.name] - end << @source_requirements[:default] + end.compact << @source_requirements[:default] + else + [] end end def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| - dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name)) name = name_for(dependency) vertex = activated.vertex_named(name) + dependency.all_sources = relevant_sources_for_vertex(vertex) [ @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, @@ -317,7 +323,7 @@ module Bundler "If you are updating multiple gems in your Gemfile at once,\n" \ "try passing them all to `bundle update`" elsif source = @source_requirements[name] - specs = source.specs[name] + specs = source.specs.search(name) versions_with_platforms = specs.map {|s| [s.version, s.platform] } message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") message << if versions_with_platforms.any? @@ -326,7 +332,7 @@ module Bundler "The source does not contain any versions of '#{name}'" end else - message = "Could not find gem '#{requirement}' in any of the gem sources " \ + message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \ "listed in your Gemfile#{cache_message}." end raise GemNotFound, message @@ -392,7 +398,7 @@ module Bundler if other_bundler_required o << "\n\n" - candidate_specs = @source_requirements[:default_bundler].specs.search(conflict_dependency) + candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency) if candidate_specs.any? target_version = candidate_specs.last.version new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") @@ -411,14 +417,8 @@ module Bundler relevant_sources = if conflict.requirement.source [conflict.requirement.source] - elsif conflict.requirement.all_sources - conflict.requirement.all_sources - elsif @lockfile_uses_separate_rubygems_sources - # every conflict should have an explicit group of sources when we - # enforce strict pinning - raise "no source set for #{conflict}" else - [] + conflict.requirement.all_sources end.compact.map(&:to_s).uniq.sort metadata_requirement = name.end_with?("\0") @@ -455,23 +455,21 @@ module Bundler def validate_resolved_specs!(resolved_specs) resolved_specs.each do |v| name = v.name - next unless sources = relevant_sources_for_vertex(v) - sources.compact! + sources = relevant_sources_for_vertex(v) + next unless sources.any? if default_index = sources.index(@source_requirements[:default]) sources.delete_at(default_index) end - sources.reject! {|s| s.specs[name].empty? } + sources.reject! {|s| s.specs.search(name).empty? } sources.uniq! next if sources.size <= 1 - multisource_disabled = Bundler.feature_flag.disable_multisource? - msg = ["The gem '#{name}' was found in multiple relevant sources."] msg.concat sources.map {|s| " * #{s}" }.sort - msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from." + msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from." msg = msg.join("\n") - raise SecurityError, msg if multisource_disabled + raise SecurityError, msg if @no_aggregate_global_source Bundler.ui.warn "Warning: #{msg}" end end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 436891256d..44b167ca3e 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -5,15 +5,19 @@ module Bundler attr_reader :path_sources, :git_sources, :plugin_sources, - :global_rubygems_source, + :global_path_source, :metadata_source + def global_rubygems_source + @global_rubygems_source ||= rubygems_aggregate_class.new + end + def initialize @path_sources = [] @git_sources = [] @plugin_sources = [] @global_rubygems_source = nil - @rubygems_aggregate = rubygems_aggregate_class.new + @global_path_source = nil @rubygems_sources = [] @metadata_source = Source::Metadata.new end @@ -22,7 +26,9 @@ module Bundler if options["gemspec"] add_source_to_list Source::Gemspec.new(options), path_sources else - add_source_to_list Source::Path.new(options), path_sources + path_source = add_source_to_list Source::Path.new(options), path_sources + @global_path_source ||= path_source if options["global"] + path_source end end @@ -41,24 +47,20 @@ module Bundler end def global_rubygems_source=(uri) - if Bundler.feature_flag.disable_multisource? - @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) - end - add_rubygems_remote(uri) + @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) end def add_rubygems_remote(uri) - return if Bundler.feature_flag.disable_multisource? - @rubygems_aggregate.add_remote(uri) - @rubygems_aggregate + global_rubygems_source.add_remote(uri) + global_rubygems_source end def default_source - global_rubygems_source || @rubygems_aggregate + global_path_source || global_rubygems_source end def rubygems_sources - @rubygems_sources + [default_source] + @rubygems_sources + [global_rubygems_source] end def rubygems_remotes @@ -94,10 +96,9 @@ module Bundler replacement_rubygems = !Bundler.feature_flag.disable_multisource? && replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } - @rubygems_aggregate = replacement_rubygems if replacement_rubygems + @global_rubygems_source = replacement_rubygems if replacement_rubygems return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) - return true if replacement_rubygems && rubygems_remotes.sort_by(&:to_s) != replacement_rubygems.remotes.sort_by(&:to_s) false end @@ -110,10 +111,6 @@ module Bundler all_sources.each(&:remote!) end - def rubygems_primary_remotes - @rubygems_aggregate.remotes - end - private def rubygems_aggregate_class diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt index 315bc745a3..8fd87abe9a 100644 --- a/lib/bundler/templates/newgem/README.md.tt +++ b/lib/bundler/templates/newgem/README.md.tt @@ -29,19 +29,21 @@ TODO: Write usage instructions here After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). +<% if config[:git] -%> ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md).<% end %> +Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %> +<% end -%> <% if config[:mit] -%> ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). <% end -%> -<% if config[:coc] -%> +<% if config[:git] && config[:coc] -%> ## Code of Conduct -Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md). +Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md). <% end -%> diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index ef8a25a2ae..46c5ecb2f3 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.12".freeze + VERSION = "2.2.13".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index c6c80637e7..609517e1e7 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.12".freeze + VERSION = "3.2.13".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/core_ext/tcpsocket_init.rb b/lib/rubygems/core_ext/tcpsocket_init.rb index 3275c58112..3d9740c579 100644 --- a/lib/rubygems/core_ext/tcpsocket_init.rb +++ b/lib/rubygems/core_ext/tcpsocket_init.rb @@ -13,12 +13,13 @@ module CoreExtensions def initialize(host, serv, *rest) mutex = Mutex.new addrs = [] + threads = [] cond_var = ConditionVariable.new Addrinfo.foreach(host, serv, nil, :STREAM) do |addr| Thread.report_on_exception = false if defined? Thread.report_on_exception = () - Thread.new(addr) do + threads << Thread.new(addr) do # give head start to ipv6 addresses sleep IPV4_DELAY_SECONDS if addr.ipv4? @@ -40,6 +41,8 @@ module CoreExtensions host = addrs.shift unless addrs.empty? end + threads.each {|t| t.kill.join if t.alive? } + super(host, serv, *rest) end end diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index fd1c0a62ac..e01d0494d6 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -66,7 +66,7 @@ class Gem::Platform when String then arch = arch.split '-' - if arch.length > 2 and arch.last !~ /\d/ # reassemble x86-linux-gnu + if arch.length > 2 and arch.last !~ /\d+(\.\d+)?$/ # reassemble x86-linux-{libc} extra = arch.pop arch.last << "-#{extra}" end @@ -146,7 +146,8 @@ class Gem::Platform ## # Does +other+ match this platform? Two platforms match if they have the # same CPU, or either has a CPU of 'universal', they have the same OS, and - # they have the same version, or either has no version. + # they have the same version, or either has no version (except for 'linux' + # where the version is the libc name, with no version standing for 'gnu') # # Additionally, the platform will match if the local CPU is 'arm' and the # other CPU starts with "arm" (for generic ARM family support). @@ -162,7 +163,10 @@ class Gem::Platform @os == other.os and # version - (@version.nil? or other.version.nil? or @version == other.version) + ( + (@os != 'linux' and (@version.nil? or other.version.nil?)) or + @version == other.version + ) end ## diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb index 8c95723bcc..d18896895e 100644 --- a/spec/bundler/bundler/plugin_spec.rb +++ b/spec/bundler/bundler/plugin_spec.rb @@ -112,6 +112,7 @@ RSpec.describe Bundler::Plugin do before do allow(Plugin::DSL).to receive(:new) { builder } allow(builder).to receive(:eval_gemfile).with(gemfile) + allow(builder).to receive(:check_primary_source_safety) allow(builder).to receive(:to_definition) { definition } allow(builder).to receive(:inferred_plugins) { [] } end diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index 5d43586116..5fa68b96d5 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -668,29 +668,40 @@ RSpec.describe "bundle exec" do subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false } - shared_examples_for "it runs" do - it "like a normally executed executable" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject - expect(exitstatus).to eq(exit_code) - expect(err).to eq(expected_err) - expect(out).to eq(expected) - end + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) end - it_behaves_like "it runs" - context "the executable exits explicitly" do let(:executable) { super() << "\nexit #{exit_code}\nputs 'POST_EXIT'\n" } context "with exit 0" do - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "with exit 99" do let(:exit_code) { 99 } - it_behaves_like "it runs" + + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end end @@ -707,7 +718,15 @@ RSpec.describe "bundle exec" do # this is specified by C99 128 + 15 end - it_behaves_like "it runs" + + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "the executable is empty" do @@ -716,7 +735,15 @@ RSpec.describe "bundle exec" do let(:exit_code) { 0 } let(:expected_err) { "#{path} is empty" } let(:expected) { "" } - it_behaves_like "it runs" + + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "the executable raises" do @@ -743,12 +770,27 @@ RSpec.describe "bundle exec" do let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\n#{system_gem_path("bin/bundle")}: Err (Err)" } let(:expected) { super() } - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when the file uses the current ruby shebang" do let(:shebang) { "#!#{Gem.ruby}" } - it_behaves_like "it runs" + + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when Bundler.setup fails", :bundler => "< 3" do @@ -762,11 +804,19 @@ RSpec.describe "bundle exec" do let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:expected) { "" } let(:expected_err) { <<-EOS.strip } -\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile.\e[0m +\e[31mCould not find gem 'rack (= 2)' in locally installed gems. +The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m EOS - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when Bundler.setup fails", :bundler => "3" do @@ -785,14 +835,28 @@ The source contains the following versions of 'rack': 1.0.0\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m EOS - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when the executable exits non-zero via at_exit" do let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" } let(:exit_code) { 1 } - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when disable_exec_load is set" do @@ -803,7 +867,14 @@ The source contains the following versions of 'rack': 1.0.0\e[0m bundle "config set disable_exec_load true" end - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "regarding $0 and __FILE__" do @@ -819,12 +890,26 @@ $0: #{path.to_s.inspect} __FILE__: #{path.to_s.inspect} EOS - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end context "when the path is relative" do let(:path) { super().relative_path_from(bundled_app) } - it_behaves_like "it runs" + it "runs" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to eq(expected_err) + expect(out).to eq(expected) + end end context "when the path is relative with a leading ./" do diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index c5294a6b4d..297d380059 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -28,44 +28,9 @@ RSpec.describe "bundle gem" do let(:require_path) { "mygem" } before do - git_config_content = <<-EOF - [user] - name = "Bundler User" - email = user@example.com - [github] - user = bundleuser - EOF - @git_config_location = ENV["GIT_CONFIG"] - path = "#{tmp}/test_git_config.txt" - File.open(path, "w") {|f| f.write(git_config_content) } - ENV["GIT_CONFIG"] = path - end - - after do - FileUtils.rm(ENV["GIT_CONFIG"]) if File.exist?(ENV["GIT_CONFIG"]) - ENV["GIT_CONFIG"] = @git_config_location - end - - shared_examples_for "git config is present" do - context "git config user.{name,email} present" do - it "sets gemspec author to git user.name if available" do - expect(generated_gemspec.authors.first).to eq("Bundler User") - end - - it "sets gemspec email to git user.email if available" do - expect(generated_gemspec.email.first).to eq("user@example.com") - end - end - end - - shared_examples_for "git config is absent" do - it "sets gemspec author to default message if git user.name is not set or empty" do - expect(generated_gemspec.authors.first).to eq("TODO: Write your name") - end - - it "sets gemspec email to default message if git user.email is not set or empty" do - expect(generated_gemspec.email.first).to eq("TODO: Write your email address") - end + sys_exec("git config --global user.name 'Bundler User'") + sys_exec("git config --global user.email user@example.com") + sys_exec("git config --global github.user bundleuser") end describe "git repo initialization" do @@ -125,19 +90,24 @@ RSpec.describe "bundle gem" do end shared_examples_for "--coc flag" do - before do - bundle "gem #{gem_name} --coc" - end it "generates a gem skeleton with MIT license" do + bundle "gem #{gem_name} --coc" gem_skeleton_assertions expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to exist end - describe "README additions" do - it "generates the README with a section for the Code of Conduct" do - expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct") - expect(bundled_app("#{gem_name}/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md") - end + it "generates the README with a section for the Code of Conduct" do + bundle "gem #{gem_name} --coc" + expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct") + expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md}) + end + + it "generates the README with a section for the Code of Conduct, respecting the configured git default branch" do + sys_exec("git config --global init.defaultBranch main") + bundle "gem #{gem_name} --coc" + + expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct") + expect(bundled_app("#{gem_name}/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/main/CODE_OF_CONDUCT.md") end end @@ -150,11 +120,9 @@ RSpec.describe "bundle gem" do expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to_not exist end - describe "README additions" do - it "generates the README without a section for the Code of Conduct" do - expect(bundled_app("#{gem_name}/README.md").read).not_to include("## Code of Conduct") - expect(bundled_app("#{gem_name}/README.md").read).not_to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md") - end + it "generates the README without a section for the Code of Conduct" do + expect(bundled_app("#{gem_name}/README.md").read).not_to include("## Code of Conduct") + expect(bundled_app("#{gem_name}/README.md").read).not_to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md}) end end @@ -302,7 +270,7 @@ RSpec.describe "bundle gem" do context "git config github.user is absent" do before do - sys_exec("git config --unset github.user") + sys_exec("git config --global --unset github.user") bundle "gem #{gem_name}" end @@ -413,17 +381,29 @@ RSpec.describe "bundle gem" do bundle "gem #{gem_name}" end - it_should_behave_like "git config is present" + it "sets gemspec author to git user.name if available" do + expect(generated_gemspec.authors.first).to eq("Bundler User") + end + + it "sets gemspec email to git user.email if available" do + expect(generated_gemspec.email.first).to eq("user@example.com") + end end context "git config user.{name,email} is not set" do before do - sys_exec("git config --unset user.name", :dir => bundled_app) - sys_exec("git config --unset user.email", :dir => bundled_app) + sys_exec("git config --global --unset user.name") + sys_exec("git config --global --unset user.email") bundle "gem #{gem_name}" end - it_should_behave_like "git config is absent" + it "sets gemspec author to default message if git user.name is not set or empty" do + expect(generated_gemspec.authors.first).to eq("TODO: Write your name") + end + + it "sets gemspec email to default message if git user.email is not set or empty" do + expect(generated_gemspec.email.first).to eq("TODO: Write your email address") + end end it "sets gemspec metadata['allowed_push_host']" do @@ -1140,7 +1120,7 @@ Usage: "bundle gem NAME [OPTIONS]" it "should fail gracefully" do FileUtils.touch(bundled_app("conflict-foobar")) bundle "gem conflict-foobar", :raise_on_error => false - expect(err).to include("Errno::ENOTDIR") + expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.") expect(exitstatus).to eql(32) end end diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb index 2c965f0ddd..3f81808980 100644 --- a/spec/bundler/commands/post_bundle_message_spec.rb +++ b/spec/bundler/commands/post_bundle_message_spec.rb @@ -113,16 +113,7 @@ RSpec.describe "post bundle message" do bundle "config set force_ruby_platform true" end - it "should report a helpful error message", :bundler => "< 3" do - install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}" - gem "rack" - gem "not-a-gem", :group => :development - G - expect(err).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile.") - end - - it "should report a helpful error message", :bundler => "3" do + it "should report a helpful error message" do install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo1)}" gem "rack" diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index 7a95a8abde..4001df26da 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -422,14 +422,13 @@ RSpec.describe "bundle install from an existing gemspec" do end end - %w[ruby jruby].each do |platform| - simulate_platform(platform) do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gemspec - G - end - end + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gemspec + G + + simulate_platform("ruby") { bundle "install" } + simulate_platform("jruby") { bundle "install" } end context "on ruby" do diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index cfa8ba7dc9..7916b83977 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -173,7 +173,7 @@ RSpec.describe "bundle install with gems on multiple sources" do it "installs from the same source without any warning" do bundle :install expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") end end @@ -187,25 +187,19 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - context "when disable_multisource is set" do - before do - bundle "config set disable_multisource true" - end - - it "installs from the same source without any warning" do - bundle :install + it "installs from the same source without any warning" do + bundle :install - expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") - # In https://github.com/bundler/bundler/issues/3585 this failed - # when there is already a lock file, and the gems are missing, so try again - system_gems [] - bundle :install + # In https://github.com/bundler/bundler/issues/3585 this failed + # when there is already a lock file, and the gems are missing, so try again + system_gems [] + bundle :install - expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") - end + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") end end end @@ -301,6 +295,33 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "when a top-level gem can only be found in an scoped source" do + before do + build_repo2 + + build_repo gem_repo3 do + build_gem "private_gem_1", "1.0.0" + build_gem "private_gem_2", "1.0.0" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + + gem "private_gem_1" + + source "#{file_uri_for(gem_repo3)}" do + gem "private_gem_2" + end + G + end + + it "fails" do + bundle :install, :raise_on_error => false + expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally.") + expect(err).to include("The source does not contain any versions of 'private_gem_1'") + end + end + context "when a top-level gem has an indirect dependency" do context "when disable_multisource is set" do before do @@ -497,6 +518,83 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved", :bundler => "< 3" do + before do + build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport") + build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s| + s.add_dependency "activesupport", "= 7.0.0.alpha" + end + + build_repo gem_repo2 do + build_gem "activesupport", "6.1.2" + + build_gem "webpacker", "5.2.1" do |s| + s.add_dependency "activesupport", ">= 5.2" + end + end + + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + + gemspec :path => "#{lib_path("rails")}" + + gem "webpacker", "~> 5.0" + G + end + + it "installs all gems without warning" do + bundle :install + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha") + expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}") + expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}") + end + end + + context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source ", :bundler => "< 3" do + before do + build_repo gem_repo3 do + build_gem "handsoap", "0.2.5.5" do |s| + s.add_dependency "nokogiri", ">= 1.2.3" + end + end + + update_repo gem_repo2 do + build_gem "nokogiri", "1.11.1" do |s| + s.add_dependency "racca", "~> 1.4" + end + + build_gem "racca", "1.5.2" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + + source "#{file_uri_for(gem_repo3)}" do + gem "handsoap" + end + + gem "nokogiri" + G + end + + it "installs from the proper sources without any warnings or errors" do + bundle "install --verbose" + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") + expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") + expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2") + + # Even if the gems are already installed + FileUtils.rm bundled_app_lock + bundle "install --verbose" + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") + expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") + expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2") + end + end + context "with a gem that is only found in the wrong source" do before do build_repo gem_repo3 do diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb index 45b68541f5..1f3c4ddaa6 100644 --- a/spec/bundler/support/indexes.rb +++ b/spec/bundler/support/indexes.rb @@ -30,7 +30,7 @@ module Spec args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter args[2] ||= [] # additional_base_requirements args[3] ||= @platforms # platforms - Bundler::Resolver.resolve(deps, @index, source_requirements, *args) + Bundler::Resolver.resolve(deps, source_requirements, *args) end def should_resolve_as(specs) diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 1c6d790b25..8b028d3495 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -1958,15 +1958,9 @@ class TestGem < Gem::TestCase io.write 'gem "a"' end - platform = Bundler::GemHelpers.generic_local_platform - if platform == Gem::Platform::RUBY - platform = '' - else - platform = " #{platform}" - end - expected = <<-EXPECTED -Could not find gem 'a#{platform}' in any of the gem sources listed in your Gemfile. +Could not find gem 'a' in locally installed gems. +The source does not contain any versions of 'a' You may need to `gem install -g` to install missing gems EXPECTED diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb index 84754402ad..ad7285c082 100644 --- a/test/rubygems/test_gem_platform.rb +++ b/test/rubygems/test_gem_platform.rb @@ -134,7 +134,9 @@ class TestGemPlatform < Gem::TestCase 'i386-solaris2.8' => ['x86', 'solaris', '2.8'], 'mswin32' => ['x86', 'mswin32', nil], 'x86_64-linux' => ['x86_64', 'linux', nil], + 'x86_64-linux-gnu' => ['x86_64', 'linux', nil], 'x86_64-linux-musl' => ['x86_64', 'linux', 'musl'], + 'x86_64-linux-uclibc' => ['x86_64', 'linux', 'uclibc'], 'x86_64-openbsd3.9' => ['x86_64', 'openbsd', '3.9'], 'x86_64-openbsd4.0' => ['x86_64', 'openbsd', '4.0'], 'x86_64-openbsd' => ['x86_64', 'openbsd', nil], @@ -143,6 +145,7 @@ class TestGemPlatform < Gem::TestCase test_cases.each do |arch, expected| platform = Gem::Platform.new arch assert_equal expected, platform.to_a, arch.inspect + assert_equal expected, Gem::Platform.new(platform.to_s).to_a, arch.inspect end end @@ -261,6 +264,32 @@ class TestGemPlatform < Gem::TestCase assert((with_x86_arch === with_nil_arch), 'x86 =~ nil') end + def test_nil_version_is_treated_as_any_version + x86_darwin_8 = Gem::Platform.new 'i686-darwin8.0' + x86_darwin_nil = Gem::Platform.new 'i686-darwin' + + assert((x86_darwin_8 === x86_darwin_nil), '8.0 =~ nil') + assert((x86_darwin_nil === x86_darwin_8), 'nil =~ 8.0') + end + + def test_nil_version_is_stricter_for_linux_os + x86_linux = Gem::Platform.new 'i686-linux' + x86_linux_gnu = Gem::Platform.new 'i686-linux-gnu' + x86_linux_musl = Gem::Platform.new 'i686-linux-musl' + x86_linux_uclibc = Gem::Platform.new 'i686-linux-uclibc' + + assert((x86_linux === x86_linux_gnu), 'linux =~ linux-gnu') + assert((x86_linux_gnu === x86_linux), 'linux-gnu =~ linux') + assert(!(x86_linux_gnu === x86_linux_musl), 'linux-gnu =~ linux-musl') + assert(!(x86_linux_musl === x86_linux_gnu), 'linux-musl =~ linux-gnu') + assert(!(x86_linux_uclibc === x86_linux_musl), 'linux-uclibc =~ linux-musl') + assert(!(x86_linux_musl === x86_linux_uclibc), 'linux-musl =~ linux-uclibc') + assert(!(x86_linux === x86_linux_musl), 'linux =~ linux-musl') + assert(!(x86_linux_musl === x86_linux), 'linux-musl =~ linux') + assert(!(x86_linux === x86_linux_uclibc), 'linux =~ linux-uclibc') + assert(!(x86_linux_uclibc === x86_linux), 'linux-uclibc =~ linux') + end + def test_equals3_cpu_arm arm = Gem::Platform.new 'arm-linux' armv5 = Gem::Platform.new 'armv5-linux' |