diff options
Diffstat (limited to 'lib')
65 files changed, 544 insertions, 372 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 9f7f9b218f..8b9e870f7b 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -69,6 +69,7 @@ module Bundler autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) autoload :Source, File.expand_path("bundler/source", __dir__) autoload :SourceList, File.expand_path("bundler/source_list", __dir__) + autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) autoload :UI, File.expand_path("bundler/ui", __dir__) diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index 6562f3a853..3027535724 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -308,39 +308,19 @@ module Bundler end end - unless Bundler.feature_flag.bundler_3_mode? - desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" - long_desc <<-D - Show lists the names and versions of all gems that are required by your Gemfile. - Calling show with [GEM] will list the exact location of that gem on your machine. - D - method_option "paths", :type => :boolean, - :banner => "List the paths of all gems that are required by your Gemfile." - method_option "outdated", :type => :boolean, - :banner => "Show verbose output including whether gems are outdated." - def show(gem_name = nil) - if ARGV[0] == "show" - rest = ARGV[1..-1] - - if flag = rest.find{|arg| ["--verbose", "--outdated"].include?(arg) } - Bundler::SharedHelpers.major_deprecation(2, "the `#{flag}` flag to `bundle show` was undocumented and will be removed without replacement") - else - new_command = rest.find {|arg| !arg.start_with?("--") } ? "info" : "list" - - new_arguments = rest.map do |arg| - next arg if arg != "--paths" - next "--path" if new_command == "info" - end - - old_argv = ARGV.join(" ") - new_argv = [new_command, *new_arguments.compact].join(" ") - - Bundler::SharedHelpers.major_deprecation(2, "use `bundle #{new_argv}` instead of `bundle #{old_argv}`") - end - end - require_relative "cli/show" - Show.new(options, gem_name).run - end + desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" + long_desc <<-D + Show lists the names and versions of all gems that are required by your Gemfile. + Calling show with [GEM] will list the exact location of that gem on your machine. + D + method_option "paths", :type => :boolean, + :banner => "List the paths of all gems that are required by your Gemfile." + method_option "outdated", :type => :boolean, + :banner => "Show verbose output including whether gems are outdated." + def show(gem_name = nil) + SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated") + require_relative "cli/show" + Show.new(options, gem_name).run end desc "list", "List all gems in the bundle" diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb index 19c0aaea06..65c51337d2 100644 --- a/lib/bundler/cli/check.rb +++ b/lib/bundler/cli/check.rb @@ -11,9 +11,11 @@ module Bundler def run Bundler.settings.set_command_option_if_given :path, options[:path] + definition = Bundler.definition + definition.validate_runtime! + begin - definition = Bundler.definition - definition.validate_runtime! + definition.resolve_only_locally! not_installed = definition.missing_specs rescue GemNotFound, VersionConflict Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index cfbf4bee6e..47c1da10e7 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -58,7 +58,10 @@ module Bundler definition.validate_runtime! installer = Installer.install(Bundler.root, definition, options) - Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? + + Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do + Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? + end Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." Bundler::CLI::Common.output_without_groups_message(:install) diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb index 7dd078b1ef..7d613a6644 100644 --- a/lib/bundler/cli/lock.rb +++ b/lib/bundler/cli/lock.rb @@ -21,9 +21,13 @@ module Bundler Bundler::Fetcher.disable_endpoint = options["full-index"] update = options[:update] + conservative = options[:conservative] + if update.is_a?(Array) # unlocking specific gems Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) - update = { :gems => update, :lock_shared_dependencies => options[:conservative] } + update = { :gems => update, :conservative => conservative } + elsif update + update = { :conservative => conservative } if conservative end definition = Bundler.definition(update) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index e5d9af477c..d5183b060b 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -146,17 +146,16 @@ module Bundler end def retrieve_active_spec(definition, current_spec) - if strict - active_spec = definition.find_resolved_spec(current_spec) - else - active_specs = definition.find_indexed_specs(current_spec) - if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 - active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - active_spec = active_specs.last - end + active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) + return unless active_spec - active_spec + return active_spec if strict + + active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) + if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 + active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } + end + active_specs.last end def print_gems(gems_list) diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb index 94699484d4..cf6a5b26d3 100644 --- a/lib/bundler/cli/update.rb +++ b/lib/bundler/cli/update.rb @@ -27,9 +27,14 @@ module Bundler raise InvalidOption, "Cannot specify --all along with specific options." end + conservative = options[:conservative] + if full_update - # We're doing a full update - Bundler.definition(true) + if conservative + Bundler.definition(:conservative => conservative) + else + Bundler.definition(true) + end else unless Bundler.default_lockfile.exist? raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ @@ -43,7 +48,7 @@ module Bundler end Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], - :lock_shared_dependencies => options[:conservative], + :conservative => conservative, :bundler => options[:bundler]) end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index fc30dd5ca8..0d7630e20d 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -112,17 +112,18 @@ module Bundler end @locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - @disable_multisource = @locked_gem_sources.all?(&:disable_multisource?) + @multisource_allowed = @locked_gem_sources.any?(&:multiple_remotes?) && Bundler.frozen_bundle? - unless @disable_multisource - msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. You should run `bundle update` or generate your lockfile from scratch." + if @multisource_allowed + unless sources.aggregate_global_source? + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." - Bundler::SharedHelpers.major_deprecation 2, msg + Bundler::SharedHelpers.major_deprecation 2, msg + end @sources.merged_gem_lockfile_sections! end - @unlock[:gems] ||= [] @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) @@ -135,8 +136,10 @@ module Bundler @path_changes = converge_paths @source_changes = converge_sources - unless @unlock[:lock_shared_dependencies] - eager_unlock = expand_dependencies(@unlock[:gems], true) + if @unlock[:conservative] + @unlock[:gems] ||= @dependencies.map(&:name) + else + eager_unlock = expand_dependencies(@unlock[:gems] || [], true) @unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name) end @@ -161,8 +164,14 @@ module Bundler end end - def disable_multisource? - @disable_multisource + def multisource_allowed? + @multisource_allowed + end + + def resolve_only_locally! + @remote = false + sources.local_only! + resolve end def resolve_with_cache! @@ -224,7 +233,6 @@ module Bundler Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true rescue BundlerError => e - @index = nil @resolve = nil @specs = nil @gem_version_promoter = nil @@ -255,7 +263,7 @@ module Bundler def specs_for(groups) deps = dependencies_for(groups) - specs.for(expand_dependencies(deps)) + SpecSet.new(specs.for(expand_dependencies(deps))) end def dependencies_for(groups) @@ -287,50 +295,6 @@ module Bundler end end - def index - @index ||= Index.build do |idx| - dependency_names = @dependencies.map(&:name) - - sources.all_sources.each do |source| - source.dependency_names = dependency_names - pinned_spec_names(source) - idx.add_source source.specs - dependency_names.concat(source.unmet_deps).uniq! - end - - double_check_for_index(idx, dependency_names) - end - end - - # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both - # sources A and B. At this point, the API request will have found all the versions of Bar in source A, - # but will not have found any versions of Bar from source B, which is a problem if the requested version - # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for - # each spec we found, we add all possible versions from all sources to the index. - def double_check_for_index(idx, dependency_names) - pinned_names = pinned_spec_names - loop do - idxcount = idx.size - - names = :names # do this so we only have to traverse to get dependency_names from the index once - unmet_dependency_names = lambda do - return names unless names == :names - new_names = sources.all_sources.map(&:dependency_names_to_double_check) - return names = nil if new_names.compact! - names = new_names.flatten(1).concat(dependency_names) - names.uniq! - names -= pinned_names - names - end - - sources.all_sources.each do |source| - source.double_check_for(unmet_dependency_names) - end - - break if idxcount == idx.size - end - end - private :double_check_for_index - def has_rubygems_remotes? sources.rubygems_sources.any? {|s| s.remotes.any? } end @@ -539,14 +503,6 @@ module Bundler end end - def find_resolved_spec(current_spec) - specs.find_by_name_and_platform(current_spec.name, current_spec.platform) - end - - def find_indexed_specs(current_spec) - index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) - end - attr_reader :sources private :sources @@ -563,6 +519,10 @@ module Bundler private + def precompute_source_requirements_for_indirect_dependencies? + sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? + end + def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY @@ -677,7 +637,7 @@ module Bundler end def converge_rubygems_sources - return false if disable_multisource? + return false unless multisource_allowed? return false if locked_gem_sources.empty? @@ -688,9 +648,9 @@ module Bundler changes = false # If there is a RubyGems source in both - locked_gem_sources.each do |locked_gem| + locked_gem_sources.each do |locked_gem_source| # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) + changes |= locked_gem_source.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) end changes @@ -789,8 +749,6 @@ module Bundler end end - unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec? - converged = [] @locked_specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile @@ -802,11 +760,6 @@ module Bundler next if s.source.nil? next if @unlock[:sources].include?(s.source.name) - # XXX This is a backwards-compatibility fix to preserve the ability to - # unlock a single gem by passing its name via `--source`. See issue #3759 - # TODO: delete in Bundler 2 - next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name) - # If the spec is from a path source and it doesn't exist anymore # then we unlock it. @@ -838,7 +791,7 @@ module Bundler resolve = SpecSet.new(converged) @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), @unlock[:gems], true, true) - resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems], false, false, false) + resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), [], false, false, false).reject{|s| @unlock[:gems].include?(s.name) }) diff = nil # Now, we unlock any sources that do not have anymore gems pinned to it @@ -909,26 +862,22 @@ module Bundler end def source_requirements - # Load all specs from remote sources - index - # 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) - source_requirements = { :default => sources.default_source }.merge(dependency_source_requirements) + source_requirements = if precompute_source_requirements_for_indirect_dependencies? + { :default => sources.default_source }.merge(source_map.all_requirements) + else + { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) + end 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[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end - def pinned_spec_names(skip = nil) - dependency_source_requirements.reject {|_, source| source == skip }.keys - end - def requested_groups groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] end @@ -984,16 +933,8 @@ 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 + def source_map + @source_map ||= SourceMap.new(sources, dependencies) end end end diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index 36c18ead22..e441b941c2 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -31,7 +31,6 @@ module Bundler settings_flag(:auto_clean_without_path) { bundler_3_mode? } settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:default_install_uses_path) { bundler_3_mode? } - settings_flag(:disable_multisource) { bundler_3_mode? } settings_flag(:forget_cli_options) { bundler_3_mode? } settings_flag(:global_gem_cache) { bundler_3_mode? } settings_flag(:path_relative_to_cwd) { bundler_3_mode? } @@ -39,7 +38,6 @@ module Bundler settings_flag(:print_only_version_number) { bundler_3_mode? } settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } - settings_flag(:unlock_source_unlocks_spec) { !bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_3_mode? } diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb index 27969d74ec..aa828af6b1 100644 --- a/lib/bundler/fetcher/compact_index.rb +++ b/lib/bundler/fetcher/compact_index.rb @@ -116,7 +116,7 @@ module Bundler def bundle_worker(func = nil) @bundle_worker ||= begin worker_name = "Compact Index (#{display_uri.host})" - Bundler::Worker.new(Bundler.current_ruby.rbx? ? 1 : 25, worker_name, func) + Bundler::Worker.new(Bundler.settings.processor_count, worker_name, func) end @bundle_worker.tap do |worker| worker.instance_variable_set(:@func, func) if func diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb index 5d30333158..f2aad3a500 100644 --- a/lib/bundler/fetcher/downloader.rb +++ b/lib/bundler/fetcher/downloader.rb @@ -68,8 +68,7 @@ module Bundler raise CertificateFailureError.new(uri) rescue *HTTP_ERRORS => e Bundler.ui.trace e - case e.message - when /host down:/, /getaddrinfo: nodename nor servname provided/ + if e.is_a?(SocketError) || e.message =~ /host down:/ raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb index 08b041897e..0d14c47aa7 100644 --- a/lib/bundler/fetcher/index.rb +++ b/lib/bundler/fetcher/index.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require_relative "base" -require "rubygems/remote_fetcher" module Bundler class Fetcher diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb index 5d0bb905bc..db43e0f654 100644 --- a/lib/bundler/friendly_errors.rb +++ b/lib/bundler/friendly_errors.rb @@ -49,8 +49,6 @@ module Bundler "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." else request_issue_report_for(error) end - rescue StandardError - raise error end def exit_status(error) @@ -111,8 +109,8 @@ module Bundler First, try this link to see if there are any existing issue reports for this error: #{issues_url(e)} - If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: - https://github.com/rubygems/rubygems/issues/new?labels=Bundler + If there aren't any reports for this error yet, please copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: + https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md EOS end diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index f945176037..36520c0a43 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -122,10 +122,9 @@ module Bundler names end - # returns a list of the dependencies def unmet_dependency_names dependency_names.select do |name| - name != "bundler" && search(name).empty? + search(name).empty? end end diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index 09c8b1c157..a88fb91cb5 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -222,14 +222,7 @@ module Bundler # Parallelization has some issues on Windows, so it's not yet the default return 1 if Gem.win_platform? - processor_count - end - - def processor_count - require "etc" - Etc.nprocessors - rescue StandardError - 1 + Bundler.settings.processor_count end def load_plugins diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index ffcd63bbcc..4945747f42 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "April 2021" "" "" +.TH "BUNDLE\-ADD" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 23c371b7de..dd43180b19 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "April 2021" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 9bb8011a8a..22ce1dfc76 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "April 2021" "" "" +.TH "BUNDLE\-CACHE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index 6696479fef..6e1b38ab05 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "April 2021" "" "" +.TH "BUNDLE\-CHECK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index 625d87c580..eb658e1c73 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "April 2021" "" "" +.TH "BUNDLE\-CLEAN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 81cfaa7165..323fcc8121 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "April 2021" "" "" +.TH "BUNDLE\-CONFIG" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options @@ -56,9 +56,6 @@ Executing \fBbundle config unset \-\-local <name> <value>\fR will delete the con .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. . -.P -Executing \fBbundle config set \-\-local disable_multisource true\fR upgrades the warning about the Gemfile containing multiple primary sources to an error\. Executing \fBbundle config unset disable_multisource\fR downgrades this error to a warning\. -. .SH "REMEMBERING OPTIONS" Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\. . @@ -184,9 +181,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. . .IP "\(bu" 4 -\fBdisable_multisource\fR (\fBBUNDLE_DISABLE_MULTISOURCE\fR): When set, Gemfiles containing multiple sources will produce errors instead of warnings\. Use \fBbundle config unset disable_multisource\fR to unset\. -. -.IP "\(bu" 4 \fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\. . .IP "\(bu" 4 @@ -280,9 +274,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. . .IP "\(bu" 4 -\fBunlock_source_unlocks_spec\fR (\fBBUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC\fR): Whether running \fBbundle update \-\-source NAME\fR unlocks a gem with the given name\. Defaults to \fBtrue\fR\. -. -.IP "\(bu" 4 \fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. . .IP "\(bu" 4 diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index b759939d3c..05ba0dc255 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -47,10 +47,6 @@ configuration only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. -Executing `bundle config set --local disable_multisource true` upgrades the warning about -the Gemfile containing multiple primary sources to an error. Executing `bundle -config unset disable_multisource` downgrades this error to a warning. - ## REMEMBERING OPTIONS Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or @@ -178,10 +174,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository. -* `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`): - When set, Gemfiles containing multiple sources will produce errors - instead of warnings. - Use `bundle config unset disable_multisource` to unset. * `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): Stop Bundler from accessing gems installed to RubyGems' normal location. * `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): @@ -268,9 +260,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. * `timeout` (`BUNDLE_TIMEOUT`): The seconds allowed before timing out for network requests. Defaults to `10`. -* `unlock_source_unlocks_spec` (`BUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC`): - Whether running `bundle update --source NAME` unlocks a gem with the given - name. Defaults to `true`. * `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): Require passing `--all` to `bundle update` when everything should be updated, and disallow passing no options to `bundle update`. diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 8e4c47c683..84d1f4c9df 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "April 2021" "" "" +.TH "BUNDLE\-DOCTOR" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 863b76e4b7..b3c60fbbfd 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "April 2021" "" "" +.TH "BUNDLE\-EXEC" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index ae4e173008..3f711c2bed 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "April 2021" "" "" +.TH "BUNDLE\-GEM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index 168d021112..337e7bdd38 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "April 2021" "" "" +.TH "BUNDLE\-INFO" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 5d3e61d05b..0c5b8c7a39 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "April 2021" "" "" +.TH "BUNDLE\-INIT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 37acabfa9a..f228ed247f 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "April 2021" "" "" +.TH "BUNDLE\-INJECT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index 2dcb4d3ac6..ae9747bd83 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "April 2021" "" "" +.TH "BUNDLE\-INSTALL" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 7c93b89dc3..cce8881059 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "April 2021" "" "" +.TH "BUNDLE\-LIST" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index a4dfda9c86..23388daaee 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "April 2021" "" "" +.TH "BUNDLE\-LOCK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index 0511bc655b..8cc104b81d 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "April 2021" "" "" +.TH "BUNDLE\-OPEN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 268b4b157c..bdd81a66af 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "April 2021" "" "" +.TH "BUNDLE\-OUTDATED" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 77638b2b4b..dab5269c04 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "April 2021" "" "" +.TH "BUNDLE\-PLATFORM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 0fcf9fdb39..e5b0dab334 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "April 2021" "" "" +.TH "BUNDLE\-PRISTINE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index ca366b81a9..8af691283d 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "April 2021" "" "" +.TH "BUNDLE\-REMOVE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index e403ae980f..c08c7205aa 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "April 2021" "" "" +.TH "BUNDLE\-SHOW" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 5546b51792..7da2ce3438 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "April 2021" "" "" +.TH "BUNDLE\-UPDATE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions @@ -79,7 +79,7 @@ Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR . .TP \fB\-\-conservative\fR -Use bundle install conservative update behavior and do not allow shared dependencies to be updated\. +Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. @@ -208,13 +208,13 @@ In this case, the two gems have their own set of dependencies, but they share \f In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. . .P -To prevent updating shared dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: +To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: . .P In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. . .P -Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent shared dependencies from being updated\. +Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. . .SH "PATCH LEVEL OPTIONS" Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. diff --git a/lib/bundler/man/bundle-update.1.ronn b/lib/bundler/man/bundle-update.1.ronn index 397fecadcb..3a16f29149 100644 --- a/lib/bundler/man/bundle-update.1.ronn +++ b/lib/bundler/man/bundle-update.1.ronn @@ -80,7 +80,7 @@ gem. Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. * `--conservative`: - Use bundle install conservative update behavior and do not allow shared dependencies to be updated. + Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. ## UPDATING ALL GEMS @@ -195,7 +195,7 @@ In short, by default, when you update a gem using `bundle update`, bundler will update all dependencies of that gem, including those that are also dependencies of another gem. -To prevent updating shared dependencies, prior to version 1.14 the only option +To prevent updating indirect dependencies, prior to version 1.14 the only option was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): In this scenario, updating the `thin` version manually in the Gemfile(5), @@ -203,7 +203,7 @@ and then running [bundle install(1)](bundle-install.1.html) will only update `da but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section of [bundle install(1)](bundle-install.1.html). -Starting with 1.14, specifying the `--conservative` option will also prevent shared +Starting with 1.14, specifying the `--conservative` option will also prevent indirect dependencies from being updated. ## PATCH LEVEL OPTIONS diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index 645c45b607..9683f0678b 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "April 2021" "" "" +.TH "BUNDLE\-VIZ" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 5c1bc96572..b741f7cf6a 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "April 2021" "" "" +.TH "BUNDLE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index c23c26ad7a..f30f71ac7c 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "April 2021" "" "" +.TH "GEMFILE" "5" "June 2021" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index d70a16f4bc..f6f4ac4f0a 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -244,6 +244,20 @@ module Bundler specs.unmet_dependency_names end + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def spec_names + specs.spec_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def add_dependency_names(names) + @dependencies |= Array(names) + end + # Note: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 660385c2ff..a78b2db157 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -21,23 +21,19 @@ module Bundler base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) - SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") }) + SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") })) end 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 = {} @base_dg = Molinillo::DependencyGraph.new + aggregate_global_source = @source_requirements[:default].is_a?(Source::RubygemsAggregate) @base.each do |ls| dep = Dependency.new(ls.name, ls.version) + ls.source = source_for(ls.name) unless aggregate_global_source @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } @@ -45,7 +41,6 @@ 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? - @no_aggregate_global_source = @source_requirements[:global].nil? end def start(requirements) @@ -55,7 +50,6 @@ module Bundler verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) dg. - tap {|resolved| validate_resolved_specs!(resolved) }. map(&:payload). reject {|sg| sg.name.end_with?("\0") }. map(&:to_specs). @@ -171,16 +165,11 @@ module Bundler end def index_for(dependency) - source = @index_requirements[dependency.name] - if source - source - elsif @no_aggregate_global_source - Index.build do |idx| - dependency.all_sources.each {|s| idx.add_source(s.specs) } - end - else - @index_requirements[:global] - end + source_for(dependency.name).specs + end + + def source_for(name) + @source_requirements[name] || @source_requirements[:default] end def results_for(dependency, base) @@ -211,23 +200,10 @@ module Bundler dependencies.map(&:dep) == other_dependencies.map(&:dep) end - def relevant_sources_for_vertex(vertex) - if vertex.root? - [@source_requirements[vertex.name]] - elsif @no_aggregate_global_source - vertex.recursive_predecessors.map do |v| - @source_requirements[v.name] - end.compact << @source_requirements[:default] - else - [] - end - end - def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| 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, @@ -369,7 +345,7 @@ module Bundler if other_bundler_required o << "\n\n" - candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency) + candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency) if candidate_specs.any? target_version = candidate_specs.last.version new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") @@ -386,11 +362,7 @@ module Bundler elsif !conflict.existing o << "\n" - relevant_sources = if conflict.requirement.source - [conflict.requirement.source] - else - conflict.requirement.all_sources - end.compact.map(&:to_s).uniq.sort + relevant_source = conflict.requirement.source || source_for(name) metadata_requirement = name.end_with?("\0") @@ -403,12 +375,10 @@ module Bundler end o << " " - o << if relevant_sources.empty? - "in any of the sources.\n" - elsif metadata_requirement - "is not available in #{relevant_sources.join(" or ")}" + o << if metadata_requirement + "is not available in #{relevant_source}" else - "in any of the relevant sources:\n #{relevant_sources * "\n "}\n" + "in #{relevant_source}.\n" end end end, @@ -422,27 +392,5 @@ module Bundler end ) end - - def validate_resolved_specs!(resolved_specs) - resolved_specs.each do |v| - name = v.name - 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.search(name).empty? } - sources.uniq! - next if sources.size <= 1 - - msg = ["The gem '#{name}' was found in multiple relevant sources."] - msg.concat sources.map {|s| " * #{s}" }.sort - 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 @no_aggregate_global_source - Bundler.ui.warn "Warning: #{msg}" - end - end end end diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 2bd2dcb451..c95664965c 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -105,7 +105,7 @@ module Gem end class Dependency - attr_accessor :source, :groups, :all_sources + attr_accessor :source, :groups alias_method :eql?, :== @@ -116,7 +116,7 @@ module Gem end def to_yaml_properties - instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) } + instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } end def to_lock diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index d060e21f50..21ce12ecda 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -526,13 +526,14 @@ module Bundler Bundler::Retry.new("download gem from #{uri}").attempts do fetcher.download(spec, uri, path) end + rescue Gem::RemoteFetcher::FetchError => e + raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>" end def gem_remote_fetcher - require "resolv" + require "rubygems/remote_fetcher" proxy = configuration[:http_proxy] - dns = Resolv::DNS.new - Gem::RemoteFetcher.new(proxy, dns) + Gem::RemoteFetcher.new(proxy) end def gem_from_path(path, policy = nil) diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index e9155acf48..95da31a765 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -20,7 +20,6 @@ module Bundler disable_exec_load disable_local_branch_check disable_local_revision_check - disable_multisource disable_shared_gems disable_version_check force_ruby_platform @@ -45,7 +44,6 @@ module Bundler silence_deprecations silence_root_warning suppress_install_using_messages - unlock_source_unlocks_spec update_requires_all_flag use_gem_version_promoter_for_major_updates ].freeze @@ -210,6 +208,13 @@ module Bundler locations end + def processor_count + require "etc" + Etc.nprocessors + rescue StandardError + 1 + end + # for legacy reasons, in Bundler 2, we do not respect :disable_shared_gems def path configs.each do |_level, settings| @@ -442,7 +447,20 @@ module Bundler valid_file = file.exist? && !file.size.zero? return {} unless valid_file require_relative "yaml_serializer" - YAMLSerializer.load file.read + YAMLSerializer.load(file.read).inject({}) do |config, (k, v)| + new_k = k + + if k.include?("-") + Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \ + "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \ + "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)." + + new_k = k.gsub("-", "___") + end + + config[new_k] = v + config + end end end diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb index a3f4b09cce..5388a7681e 100644 --- a/lib/bundler/source.rb +++ b/lib/bundler/source.rb @@ -7,6 +7,7 @@ module Bundler autoload :Metadata, File.expand_path("source/metadata", __dir__) autoload :Path, File.expand_path("source/path", __dir__) autoload :Rubygems, File.expand_path("source/rubygems", __dir__) + autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) attr_accessor :dependency_names @@ -35,10 +36,16 @@ module Bundler def local!; end + def local_only!; end + def cached!; end def remote!; end + def add_dependency_names(names) + @dependency_names = Array(dependency_names) | Array(names) + end + # it's possible that gems from one source depend on gems from some # other source, so now we download gemspecs and iterate over those # dependencies, looking for gems we don't have info on yet. @@ -48,6 +55,10 @@ module Bundler specs.dependency_names end + def spec_names + specs.spec_names + end + def include?(other) other == self end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 2b7cfd53b9..b4bb3d1980 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -26,6 +26,12 @@ module Bundler Array(options["remotes"]).reverse_each {|r| add_remote(r) } end + def local_only! + @specs = nil + @allow_local = true + @allow_remote = false + end + def local! return if @allow_local @@ -61,13 +67,13 @@ module Bundler o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? end - def disable_multisource? - @remotes.size <= 1 + def multiple_remotes? + @remotes.size > 1 end def can_lock?(spec) - return super if disable_multisource? - spec.source.is_a?(Rubygems) + return super unless multiple_remotes? + include?(spec.source) end def options @@ -259,8 +265,16 @@ module Bundler !equivalent end + def spec_names + if @allow_remote && dependency_api_available? + remote_specs.spec_names + else + [] + end + end + def unmet_deps - if @allow_remote && api_fetchers.any? + if @allow_remote && dependency_api_available? remote_specs.unmet_dependency_names else [] @@ -276,7 +290,7 @@ module Bundler def double_check_for(unmet_dependency_names) return unless @allow_remote - return unless api_fetchers.any? + return unless dependency_api_available? unmet_dependency_names = unmet_dependency_names.call unless unmet_dependency_names.nil? @@ -298,17 +312,20 @@ module Bundler remote_specs.each do |spec| case spec when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification - names.concat(spec.runtime_dependencies) + names.concat(spec.runtime_dependencies.map(&:name)) when RemoteSpecification # from the full index return nil else raise "unhandled spec type (#{spec.inspect})" end end - names.map!(&:name) if names names end + def dependency_api_available? + api_fetchers.any? + end + protected def credless_remotes @@ -387,10 +404,6 @@ module Bundler next if gemfile =~ /^bundler\-[\d\.]+?\.gem/ s ||= Bundler.rubygems.spec_from_gem(gemfile) s.source = self - if Bundler.rubygems.spec_missing_extensions?(s, false) - Bundler.ui.debug "Source #{self} is ignoring #{s} because it is missing extensions" - next - end idx << s end diff --git a/lib/bundler/source/rubygems_aggregate.rb b/lib/bundler/source/rubygems_aggregate.rb new file mode 100644 index 0000000000..685bf7e90a --- /dev/null +++ b/lib/bundler/source/rubygems_aggregate.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Bundler + class Source + class RubygemsAggregate + attr_reader :source_map, :sources + + def initialize(sources, source_map) + @sources = sources + @source_map = source_map + + @index = build_index + end + + def specs + @index + end + + def to_s + "any of the sources" + end + + private + + def build_index + Index.build do |idx| + dependency_names = source_map.pinned_spec_names + + sources.all_sources.each do |source| + source.dependency_names = dependency_names - source_map.pinned_spec_names(source) + idx.add_source source.specs + dependency_names.concat(source.unmet_deps).uniq! + end + + double_check_for_index(idx, dependency_names) + end + end + + # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both + # sources A and B. At this point, the API request will have found all the versions of Bar in source A, + # but will not have found any versions of Bar from source B, which is a problem if the requested version + # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for + # each spec we found, we add all possible versions from all sources to the index. + def double_check_for_index(idx, dependency_names) + pinned_names = source_map.pinned_spec_names + + names = :names # do this so we only have to traverse to get dependency_names from the index once + unmet_dependency_names = lambda do + return names unless names == :names + new_names = sources.all_sources.map(&:dependency_names_to_double_check) + return names = nil if new_names.compact! + names = new_names.flatten(1).concat(dependency_names) + names.uniq! + names -= pinned_names + names + end + + sources.all_sources.each do |source| + source.double_check_for(unmet_dependency_names) + end + end + end + end +end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 6f5636f41e..9a7f0ea0a2 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -21,15 +21,19 @@ module Bundler @rubygems_sources = [] @metadata_source = Source::Metadata.new - @disable_multisource = true + @merged_gem_lockfile_sections = false end - def disable_multisource? - @disable_multisource + def merged_gem_lockfile_sections? + @merged_gem_lockfile_sections end def merged_gem_lockfile_sections! - @disable_multisource = false + @merged_gem_lockfile_sections = true + end + + def aggregate_global_source? + global_rubygems_source.multiple_remotes? end def add_path_source(options = {}) @@ -70,7 +74,11 @@ module Bundler end def rubygems_sources - @rubygems_sources + [global_rubygems_source] + non_global_rubygems_sources + [global_rubygems_source] + end + + def non_global_rubygems_sources + @rubygems_sources end def rubygems_remotes @@ -81,16 +89,27 @@ module Bundler path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end + def non_default_explicit_sources + all_sources - [default_source, metadata_source] + end + def get(source) source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) } end def lock_sources - lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) - if disable_multisource? - lock_sources + rubygems_sources.sort_by(&:to_s).uniq + lock_other_sources + lock_rubygems_sources + end + + def lock_other_sources + (path_sources + git_sources + plugin_sources).sort_by(&:to_s) + end + + def lock_rubygems_sources + if merged_gem_lockfile_sections? + [combine_rubygems_sources] else - lock_sources << combine_rubygems_sources + rubygems_sources.sort_by(&:to_s).uniq end end @@ -104,7 +123,7 @@ module Bundler end end - replacement_rubygems = !disable_multisource? && + replacement_rubygems = merged_gem_lockfile_sections? && replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } @global_rubygems_source = replacement_rubygems if replacement_rubygems @@ -113,6 +132,10 @@ module Bundler false end + def local_only! + all_sources.each(&:local_only!) + end + def cached! all_sources.each(&:cached!) end @@ -162,6 +185,8 @@ module Bundler end def equal_source?(source, other_source) + return source.include?(other_source) if source.is_a?(Source::Rubygems) && other_source.is_a?(Source::Rubygems) && !merged_gem_lockfile_sections? + source == other_source end diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb new file mode 100644 index 0000000000..a554f26f76 --- /dev/null +++ b/lib/bundler/source_map.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Bundler + class SourceMap + attr_reader :sources, :dependencies + + def initialize(sources, dependencies) + @sources = sources + @dependencies = dependencies + end + + def pinned_spec_names(skip = nil) + direct_requirements.reject {|_, source| source == skip }.keys + end + + def all_requirements + requirements = direct_requirements.dup + + unmet_deps = sources.non_default_explicit_sources.map do |source| + (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| + previous_source = requirements[indirect_dependency_name] + if previous_source.nil? + requirements[indirect_dependency_name] = source + else + no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode? + + msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] + msg.concat [previous_source, source].map {|s| " * #{s}" }.sort + msg << "You #{no_ambiguous_sources ? :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 no_ambiguous_sources + Bundler.ui.warn "Warning: #{msg}" + end + end + + source.unmet_deps + end + + sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) + + requirements + end + + def direct_requirements + @direct_requirements ||= begin + requirements = {} + default = sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + dep_source.add_dependency_names(dep.name) + requirements[dep.name] = dep_source + end + requirements + end + end + end +end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 67669cdd0e..af16984454 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -46,11 +46,7 @@ module Bundler specs << spec end - check ? true : SpecSet.new(specs) - end - - def valid_for?(deps) - self.for(deps, [], true) + check ? true : specs end def [](key) @@ -77,7 +73,7 @@ module Bundler end def materialize(deps, missing_specs = nil) - materialized = self.for(deps, [], false, true, !missing_specs).to_a + materialized = self.for(deps, [], false, true, !missing_specs) materialized.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index d961d615b4..eddb8b4a30 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -14,9 +14,9 @@ Gem::Specification.new do |spec| <%- if config[:mit] -%> spec.license = "MIT" <%- end -%> - spec.required_ruby_version = Gem::Requirement.new(">= <%= config[:required_ruby_version] %>") + spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" + spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'" spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index 9f935e6285..303f54a7d7 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -355,6 +355,8 @@ class Gem::Command def add_option(*opts, &handler) # :yields: value, options group_name = Symbol === opts.first ? opts.shift : :options + raise "Do not pass an empty string in opts" if opts.include?("") + @option_groups[group_name] << [opts, handler] end diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb index fff5f7c76f..842ec1855a 100644 --- a/lib/rubygems/commands/build_command.rb +++ b/lib/rubygems/commands/build_command.rb @@ -23,7 +23,7 @@ class Gem::Commands::BuildCommand < Gem::Command options[:output] = value end - add_option '-C PATH', '', 'Run as if gem build was started in <PATH> instead of the current working directory.' do |value, options| + add_option '-C PATH', 'Run as if gem build was started in <PATH> instead of the current working directory.' do |value, options| options[:build_path] = value end end diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb index 998df0621b..3fc0daea7d 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -7,37 +7,9 @@ class Gem::Commands::CertCommand < Gem::Command super 'cert', 'Manage RubyGems certificates and signing settings', :add => [], :remove => [], :list => [], :build => [], :sign => [] - OptionParser.accept OpenSSL::X509::Certificate do |certificate_file| - begin - certificate = OpenSSL::X509::Certificate.new File.read certificate_file - rescue Errno::ENOENT - raise OptionParser::InvalidArgument, "#{certificate_file}: does not exist" - rescue OpenSSL::X509::CertificateError - raise OptionParser::InvalidArgument, - "#{certificate_file}: invalid X509 certificate" - end - [certificate, certificate_file] - end - - OptionParser.accept OpenSSL::PKey::RSA do |key_file| - begin - passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] - key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase - rescue Errno::ENOENT - raise OptionParser::InvalidArgument, "#{key_file}: does not exist" - rescue OpenSSL::PKey::RSAError - raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key" - end - - raise OptionParser::InvalidArgument, - "#{key_file}: private key not found" unless key.private? - - key - end - - add_option('-a', '--add CERT', OpenSSL::X509::Certificate, - 'Add a trusted certificate.') do |(cert, _), options| - options[:add] << cert + add_option('-a', '--add CERT', + 'Add a trusted certificate.') do |cert_file, options| + options[:add] << open_cert(cert_file) end add_option('-l', '--list [FILTER]', @@ -60,15 +32,15 @@ class Gem::Commands::CertCommand < Gem::Command options[:build] << email_address end - add_option('-C', '--certificate CERT', OpenSSL::X509::Certificate, - 'Signing certificate for --sign') do |(cert, cert_file), options| - options[:issuer_cert] = cert + add_option('-C', '--certificate CERT', + 'Signing certificate for --sign') do |cert_file, options| + options[:issuer_cert] = open_cert(cert_file) options[:issuer_cert_file] = cert_file end - add_option('-K', '--private-key KEY', OpenSSL::PKey::RSA, - 'Key for --sign or --build') do |key, options| - options[:key] = key + add_option('-K', '--private-key KEY', + 'Key for --sign or --build') do |key_file, options| + options[:key] = open_private_key(key_file) end add_option('-s', '--sign CERT', @@ -97,7 +69,39 @@ class Gem::Commands::CertCommand < Gem::Command say "Added '#{certificate.subject}'" end + def check_openssl + return if Gem::HAVE_OPENSSL + + alert_error "OpenSSL library is required for the cert command" + terminate_interaction 1 + end + + def open_cert(certificate_file) + check_openssl + OpenSSL::X509::Certificate.new File.read certificate_file + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{certificate_file}: does not exist" + rescue OpenSSL::X509::CertificateError + raise OptionParser::InvalidArgument, + "#{certificate_file}: invalid X509 certificate" + end + + def open_private_key(key_file) + check_openssl + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase + raise OptionParser::InvalidArgument, + "#{key_file}: private key not found" unless key.private? + key + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{key_file}: does not exist" + rescue OpenSSL::PKey::RSAError + raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key" + end + def execute + check_openssl + options[:add].each do |certificate| add_certificate certificate end @@ -311,4 +315,4 @@ For further reading on signing gems see `ri Gem::Security`. # It's simple, but is all we need email =~ /\A.+@.+\z/ end -end if Gem::HAVE_OPENSSL +end diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 9dc41a2995..3746d7aab0 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -320,7 +320,7 @@ if you believe they were disclosed to a third party. config = load_file(credentials_path).merge(host => api_key) dirname = File.dirname credentials_path - Dir.mkdir(dirname) unless File.exist? dirname + FileUtils.mkdir_p(dirname) unless File.exist? dirname Gem.load_yaml diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index fede270417..1f73796351 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -23,11 +23,11 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder # spaces do not work. # # Details: https://github.com/rubygems/rubygems/issues/977#issuecomment-171544940 - tmp_dest = get_relative_path(tmp_dest, extension_dir) + tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir) Tempfile.open %w[siteconf .rb], extension_dir do |siteconf| siteconf.puts "require 'rbconfig'" - siteconf.puts "dest_path = #{tmp_dest.dump}" + siteconf.puts "dest_path = #{tmp_dest_relative.dump}" %w[sitearchdir sitelibdir].each do |dir| siteconf.puts "RbConfig::MAKEFILE_CONFIG['#{dir}'] = dest_path" siteconf.puts "RbConfig::CONFIG['#{dir}'] = dest_path" @@ -63,8 +63,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder make dest_path, results, extension_dir - if tmp_dest - full_tmp_dest = File.join(extension_dir, tmp_dest) + if tmp_dest_relative + full_tmp_dest = File.join(extension_dir, tmp_dest_relative) # TODO remove in RubyGems 3 if Gem.install_extension_in_lib and lib_dir diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 7af51056b7..8c286605e1 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -728,6 +728,10 @@ class Gem::Installer raise Gem::InstallError, "#{spec} has an invalid extensions" end + if spec.platform.to_s =~ /\R/ + raise Gem::InstallError, "#{spec.platform} is an invalid platform" + end + unless spec.specification_version.to_s =~ /\A\d+\z/ raise Gem::InstallError, "#{spec} has an invalid specification_version" end diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb index 1ed0fbcb99..5bda0b2e5e 100644 --- a/lib/rubygems/request.rb +++ b/lib/rubygems/request.rb @@ -44,7 +44,7 @@ class Gem::Request end def self.configure_connection_for_https(connection, cert_files) - raise Gem::Exception.new('OpenSSl is not available. Install OpenSSL and rebuild Ruby (preferred) or use non-HTTPS sources') unless Gem::HAVE_OPENSSL + raise Gem::Exception.new('OpenSSL is not available. Install OpenSSL and rebuild Ruby (preferred) or use non-HTTPS sources') unless Gem::HAVE_OPENSSL connection.use_ssl = true connection.verify_mode = diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 7206c3eaf0..23a37e966b 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -2421,7 +2421,6 @@ class Gem::Specification < Gem::BasicSpecification # still have their default values are omitted. def to_ruby - require_relative 'openssl' mark_version result = [] result << "# -*- encoding: utf-8 -*-" @@ -2455,16 +2454,21 @@ class Gem::Specification < Gem::BasicSpecification :has_rdoc, :default_executable, :metadata, + :signing_key, ] @@attributes.each do |attr_name| next if handled.include? attr_name current_value = self.send(attr_name) if current_value != default_value(attr_name) || self.class.required_attribute?(attr_name) - result << " s.#{attr_name} = #{ruby_code current_value}" unless defined?(OpenSSL::PKey::RSA) && current_value.is_a?(OpenSSL::PKey::RSA) + result << " s.#{attr_name} = #{ruby_code current_value}" end end + if String === signing_key + result << " s.signing_key = #{signing_key.dump}.freeze" + end + if @installed_by_version result << nil result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version" diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index 2b8b05635e..86277a2058 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -124,25 +124,26 @@ class Gem::SpecificationPolicy end metadata.each do |key, value| + entry = "metadata['#{key}']" if !key.kind_of?(String) error "metadata keys must be a String" end if key.size > 128 - error "metadata key too large (#{key.size} > 128)" + error "metadata key is too large (#{key.size} > 128)" end if !value.kind_of?(String) - error "metadata values must be a String" + error "#{entry} value must be a String" end if value.size > 1024 - error "metadata value too large (#{value.size} > 1024)" + error "#{entry} value is too large (#{value.size} > 1024)" end if METADATA_LINK_KEYS.include? key if value !~ VALID_URI_PATTERN - error "metadata['#{key}'] has invalid link: #{value.inspect}" + error "#{entry} has invalid link: #{value.inspect}" end end end diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index 51ac3494f3..3bc202863c 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -261,7 +261,10 @@ class Gem::Uninstaller safe_delete { FileUtils.rm_r gem } - Gem::RDoc.new(spec).remove + begin + Gem::RDoc.new(spec).remove + rescue NameError + end gemspec = spec.spec_file diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb index 29bf310ea0..98cbd8929b 100644 --- a/lib/rubygems/util/licenses.rb +++ b/lib/rubygems/util/licenses.rb @@ -18,6 +18,8 @@ class Gem::Licenses AFL-2.1 AFL-3.0 AGPL-1.0 + AGPL-1.0-only + AGPL-1.0-or-later AGPL-3.0 AGPL-3.0-only AGPL-3.0-or-later @@ -25,6 +27,7 @@ class Gem::Licenses AML AMPAS ANTLR-PD + ANTLR-PD-fallback APAFML APL-1.0 APSL-1.0 @@ -48,29 +51,41 @@ class Gem::Licenses BSD-2-Clause-FreeBSD BSD-2-Clause-NetBSD BSD-2-Clause-Patent + BSD-2-Clause-Views BSD-3-Clause BSD-3-Clause-Attribution BSD-3-Clause-Clear BSD-3-Clause-LBNL + BSD-3-Clause-Modification + BSD-3-Clause-No-Military-License BSD-3-Clause-No-Nuclear-License BSD-3-Clause-No-Nuclear-License-2014 BSD-3-Clause-No-Nuclear-Warranty + BSD-3-Clause-Open-MPI BSD-4-Clause + BSD-4-Clause-Shortened BSD-4-Clause-UC BSD-Protection BSD-Source-Code BSL-1.0 + BUSL-1.1 Bahyph Barr Beerware BitTorrent-1.0 BitTorrent-1.1 + BlueOak-1.0.0 Borceux + C-UDA-1.0 + CAL-1.0 + CAL-1.0-Combined-Work-Exception CATOSL-1.1 CC-BY-1.0 CC-BY-2.0 CC-BY-2.5 CC-BY-3.0 + CC-BY-3.0-AT + CC-BY-3.0-US CC-BY-4.0 CC-BY-NC-1.0 CC-BY-NC-2.0 @@ -81,6 +96,7 @@ class Gem::Licenses CC-BY-NC-ND-2.0 CC-BY-NC-ND-2.5 CC-BY-NC-ND-3.0 + CC-BY-NC-ND-3.0-IGO CC-BY-NC-ND-4.0 CC-BY-NC-SA-1.0 CC-BY-NC-SA-2.0 @@ -94,12 +110,17 @@ class Gem::Licenses CC-BY-ND-4.0 CC-BY-SA-1.0 CC-BY-SA-2.0 + CC-BY-SA-2.0-UK + CC-BY-SA-2.1-JP CC-BY-SA-2.5 CC-BY-SA-3.0 + CC-BY-SA-3.0-AT CC-BY-SA-4.0 + CC-PDDC CC0-1.0 CDDL-1.0 CDDL-1.1 + CDL-1.0 CDLA-Permissive-1.0 CDLA-Sharing-1.0 CECILL-1.0 @@ -108,6 +129,11 @@ class Gem::Licenses CECILL-2.1 CECILL-B CECILL-C + CERN-OHL-1.1 + CERN-OHL-1.2 + CERN-OHL-P-2.0 + CERN-OHL-S-2.0 + CERN-OHL-W-2.0 CNRI-Jython CNRI-Python CNRI-Python-GPL-Compatible @@ -123,12 +149,14 @@ class Gem::Licenses Cube D-FSL-1.0 DOC + DRL-1.0 DSDP Dotseqn ECL-1.0 ECL-2.0 EFL-1.0 EFL-2.0 + EPICS EPL-1.0 EPL-2.0 EUDatagrid @@ -144,17 +172,32 @@ class Gem::Licenses FTL Fair Frameworx-1.0 + FreeBSD-DOC FreeImage + GD GFDL-1.1 + GFDL-1.1-invariants-only + GFDL-1.1-invariants-or-later + GFDL-1.1-no-invariants-only + GFDL-1.1-no-invariants-or-later GFDL-1.1-only GFDL-1.1-or-later GFDL-1.2 + GFDL-1.2-invariants-only + GFDL-1.2-invariants-or-later + GFDL-1.2-no-invariants-only + GFDL-1.2-no-invariants-or-later GFDL-1.2-only GFDL-1.2-or-later GFDL-1.3 + GFDL-1.3-invariants-only + GFDL-1.3-invariants-or-later + GFDL-1.3-no-invariants-only + GFDL-1.3-no-invariants-or-later GFDL-1.3-only GFDL-1.3-or-later GL2PS + GLWTPL GPL-1.0 GPL-1.0+ GPL-1.0-only @@ -178,7 +221,10 @@ class Gem::Licenses Glide Glulxe HPND + HPND-sell-variant + HTMLTIDY HaskellReport + Hippocratic-2.1 IBM-pibs ICU IJG @@ -191,6 +237,7 @@ class Gem::Licenses Intel Intel-ACPI Interbase-1.0 + JPNIC JSON JasPer-2.0 LAL-1.2 @@ -221,11 +268,15 @@ class Gem::Licenses LiLiQ-R-1.1 LiLiQ-Rplus-1.1 Libpng + Linux-OpenIB MIT + MIT-0 MIT-CMU + MIT-Modern-Variant MIT-advertising MIT-enna MIT-feh + MIT-open-group MITNFA MPL-1.0 MPL-1.1 @@ -237,12 +288,18 @@ class Gem::Licenses MakeIndex MirOS Motosoto + MulanPSL-1.0 + MulanPSL-2.0 Multics Mup + NAIST-2003 NASA-1.3 NBPL-1.0 + NCGL-UK-2.0 NCSA NGPL + NIST-PD + NIST-PD-fallback NLOD-1.0 NLPL NOSL @@ -251,6 +308,7 @@ class Gem::Licenses NPOSL-3.0 NRL NTP + NTP-0 Naumen Net-SNMP NetCDF @@ -258,11 +316,23 @@ class Gem::Licenses Nokia Noweb Nunit + O-UDA-1.0 OCCT-PL OCLC-2.0 + ODC-By-1.0 ODbL-1.0 OFL-1.0 + OFL-1.0-RFN + OFL-1.0-no-RFN OFL-1.1 + OFL-1.1-RFN + OFL-1.1-no-RFN + OGC-1.0 + OGDL-Taiwan-1.0 + OGL-Canada-2.0 + OGL-UK-1.0 + OGL-UK-2.0 + OGL-UK-3.0 OGTSL OLDAP-1.1 OLDAP-1.2 @@ -292,7 +362,12 @@ class Gem::Licenses PDDL-1.0 PHP-3.0 PHP-3.01 + PSF-2.0 + Parity-6.0.0 + Parity-7.0.0 Plexus + PolyForm-Noncommercial-1.0.0 + PolyForm-Small-Business-1.0.0 PostgreSQL Python-2.0 QPL-1.0 @@ -310,15 +385,21 @@ class Gem::Licenses SGI-B-1.0 SGI-B-1.1 SGI-B-2.0 + SHL-0.5 + SHL-0.51 SISSL SISSL-1.2 SMLNJ SMPPL SNIA SPL-1.0 + SSH-OpenSSH + SSH-short + SSPL-1.0 SWL Saxpath Sendmail + Sendmail-8.23 SimPL-2.0 Sleepycat Spencer-86 @@ -326,11 +407,15 @@ class Gem::Licenses Spencer-99 StandardML-NJ SugarCRM-1.1.3 + TAPR-OHL-1.0 TCL TCP-wrappers TMate TORQUE-1.1 TOSL + TU-Berlin-1.0 + TU-Berlin-2.0 + UCL-1.0 UPL-1.0 Unicode-DFS-2015 Unicode-DFS-2016 @@ -360,16 +445,22 @@ class Gem::Licenses Zimbra-1.3 Zimbra-1.4 Zlib + blessing bzip2-1.0.5 bzip2-1.0.6 + copyleft-next-0.3.0 + copyleft-next-0.3.1 curl diffmark dvipdfm eCos-2.0 eGenix + etalab-2.0 gSOAP-1.3b gnuplot iMatix + libpng-2.0 + libselinux-1.0 libtiff mpich2 psfrag @@ -395,12 +486,26 @@ class Gem::Licenses Font-exception-2.0 GCC-exception-2.0 GCC-exception-3.1 + GPL-3.0-linking-exception + GPL-3.0-linking-source-exception + GPL-CC-1.0 + LGPL-3.0-linking-exception + LLVM-exception LZMA-exception Libtool-exception Linux-syscall-note Nokia-Qt-exception-1.1 OCCT-exception-1.0 + OCaml-LGPL-linking-exception + OpenJDK-assembly-exception-1.0 + PS-or-PDF-font-exception-20170817 + Qt-GPL-exception-1.0 + Qt-LGPL-exception-1.1 Qwt-exception-1.0 + SHL-2.0 + SHL-2.1 + Swift-exception + Universal-FOSS-exception-1.0 WxWindows-exception-3.1 eCos-exception-2.0 freertos-exception-2.0 @@ -413,10 +518,10 @@ class Gem::Licenses REGEXP = %r{ \A - ( + (?: #{Regexp.union(LICENSE_IDENTIFIERS)} \+? - (\s WITH \s #{Regexp.union(EXCEPTION_IDENTIFIERS)})? + (?:\s WITH \s #{Regexp.union(EXCEPTION_IDENTIFIERS)})? | #{NONSTANDARD} ) \Z |