1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Update bundled bundler to 1.16.0.

* lib/bundler, spec/bundler: Merge bundler-1.16.0.
  * common.mk: rspec examples of bundler-1.16.0 needs require option.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60603 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
hsbt 2017-11-01 23:29:38 +00:00
parent ae49dbd392
commit be7b592912
1025 changed files with 13902 additions and 3180 deletions

View file

@ -23,7 +23,7 @@ Bundler.with_friendly_errors do
require "bundler/cli" require "bundler/cli"
# Allow any command to use --help flag to show help for that command # Allow any command to use --help flag to show help for that command
help_flags = %w(--help -h) help_flags = %w[--help -h]
help_flag_used = ARGV.any? {|a| help_flags.include? a } help_flag_used = ARGV.any? {|a| help_flags.include? a }
args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV

View file

@ -1185,7 +1185,7 @@ test-bundler: $(TEST_RUNNABLE)-test-bundler
yes-test-bundler: yes-test-bundler-prepare yes-test-bundler: yes-test-bundler-prepare
$(gnumake_recursive)$(Q) \ $(gnumake_recursive)$(Q) \
$(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec \ $(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec \
$(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS) --require spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
no-test-bundler: no-test-bundler:
UNICODE_FILES = $(UNICODE_SRC_DATA_DIR)/UnicodeData.txt \ UNICODE_FILES = $(UNICODE_SRC_DATA_DIR)/UnicodeData.txt \

View file

@ -1,8 +1,8 @@
# coding: utf-8 # coding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
lib = File.expand_path("../lib/", __FILE__)
$:.unshift lib unless $:.include?(lib) require File.expand_path("../bundler/version", __FILE__)
require "bundler/version" require "shellwords"
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "bundler" s.name = "bundler"
@ -27,225 +27,315 @@ Gem::Specification.new do |s|
} }
end end
if s.version >= Gem::Version.new("2.a".dup)
s.required_ruby_version = ">= 2.3.0"
s.required_rubygems_version = ">= 2.5.0"
else
s.required_ruby_version = ">= 1.8.7" s.required_ruby_version = ">= 1.8.7"
s.required_rubygems_version = ">= 1.3.6" s.required_rubygems_version = ">= 1.3.6"
end
s.add_development_dependency "automatiek", "~> 0.1.0" s.add_development_dependency "automatiek", "~> 0.1.0"
s.add_development_dependency "mustache", "0.99.6" s.add_development_dependency "mustache", "0.99.6"
s.add_development_dependency "rake", "~> 10.0" s.add_development_dependency "rake", "~> 10.0"
s.add_development_dependency "rdiscount", "~> 2.2" s.add_development_dependency "rdiscount", "~> 2.2"
s.add_development_dependency "ronn", "~> 0.7.3" s.add_development_dependency "ronn", "~> 0.7.3"
s.add_development_dependency "rspec", "~> 3.5" s.add_development_dependency "rspec", "~> 3.6"
s.files = [ s.files = %w[
"lib/bundler.gemspec", exe/bundle
"bin/bundle", exe/bundle_ruby
"bin/bundle_ruby", exe/bundler
"bin/bundler", lib/bundler.rb
"lib/bundler.rb", lib/bundler/build_metadata.rb
"lib/bundler/capistrano.rb", lib/bundler/capistrano.rb
"lib/bundler/cli.rb", lib/bundler/cli.rb
"lib/bundler/cli/add.rb", lib/bundler/cli/add.rb
"lib/bundler/cli/binstubs.rb", lib/bundler/cli/binstubs.rb
"lib/bundler/cli/cache.rb", lib/bundler/cli/cache.rb
"lib/bundler/cli/check.rb", lib/bundler/cli/check.rb
"lib/bundler/cli/clean.rb", lib/bundler/cli/clean.rb
"lib/bundler/cli/common.rb", lib/bundler/cli/common.rb
"lib/bundler/cli/config.rb", lib/bundler/cli/config.rb
"lib/bundler/cli/console.rb", lib/bundler/cli/console.rb
"lib/bundler/cli/doctor.rb", lib/bundler/cli/doctor.rb
"lib/bundler/cli/exec.rb", lib/bundler/cli/exec.rb
"lib/bundler/cli/gem.rb", lib/bundler/cli/gem.rb
"lib/bundler/cli/info.rb", lib/bundler/cli/info.rb
"lib/bundler/cli/init.rb", lib/bundler/cli/init.rb
"lib/bundler/cli/inject.rb", lib/bundler/cli/inject.rb
"lib/bundler/cli/install.rb", lib/bundler/cli/install.rb
"lib/bundler/cli/issue.rb", lib/bundler/cli/issue.rb
"lib/bundler/cli/lock.rb", lib/bundler/cli/list.rb
"lib/bundler/cli/open.rb", lib/bundler/cli/lock.rb
"lib/bundler/cli/outdated.rb", lib/bundler/cli/open.rb
"lib/bundler/cli/package.rb", lib/bundler/cli/outdated.rb
"lib/bundler/cli/platform.rb", lib/bundler/cli/package.rb
"lib/bundler/cli/plugin.rb", lib/bundler/cli/platform.rb
"lib/bundler/cli/pristine.rb", lib/bundler/cli/plugin.rb
"lib/bundler/cli/show.rb", lib/bundler/cli/pristine.rb
"lib/bundler/cli/update.rb", lib/bundler/cli/show.rb
"lib/bundler/cli/viz.rb", lib/bundler/cli/update.rb
"lib/bundler/compact_index_client.rb", lib/bundler/cli/viz.rb
"lib/bundler/compact_index_client/cache.rb", lib/bundler/compact_index_client.rb
"lib/bundler/compact_index_client/updater.rb", lib/bundler/compact_index_client/cache.rb
"lib/bundler/constants.rb", lib/bundler/compact_index_client/updater.rb
"lib/bundler/current_ruby.rb", lib/bundler/compatibility_guard.rb
"lib/bundler/definition.rb", lib/bundler/constants.rb
"lib/bundler/dep_proxy.rb", lib/bundler/current_ruby.rb
"lib/bundler/dependency.rb", lib/bundler/definition.rb
"lib/bundler/deployment.rb", lib/bundler/dep_proxy.rb
"lib/bundler/deprecate.rb", lib/bundler/dependency.rb
"lib/bundler/dsl.rb", lib/bundler/deployment.rb
"lib/bundler/endpoint_specification.rb", lib/bundler/deprecate.rb
"lib/bundler/env.rb", lib/bundler/dsl.rb
"lib/bundler/environment_preserver.rb", lib/bundler/endpoint_specification.rb
"lib/bundler/errors.rb", lib/bundler/env.rb
"lib/bundler/feature_flag.rb", lib/bundler/environment_preserver.rb
"lib/bundler/fetcher.rb", lib/bundler/errors.rb
"lib/bundler/fetcher/base.rb", lib/bundler/feature_flag.rb
"lib/bundler/fetcher/compact_index.rb", lib/bundler/fetcher.rb
"lib/bundler/fetcher/dependency.rb", lib/bundler/fetcher/base.rb
"lib/bundler/fetcher/downloader.rb", lib/bundler/fetcher/compact_index.rb
"lib/bundler/fetcher/index.rb", lib/bundler/fetcher/dependency.rb
"lib/bundler/friendly_errors.rb", lib/bundler/fetcher/downloader.rb
"lib/bundler/gem_helper.rb", lib/bundler/fetcher/index.rb
"lib/bundler/gem_helpers.rb", lib/bundler/friendly_errors.rb
"lib/bundler/gem_remote_fetcher.rb", lib/bundler/gem_helper.rb
"lib/bundler/gem_tasks.rb", lib/bundler/gem_helpers.rb
"lib/bundler/gem_version_promoter.rb", lib/bundler/gem_remote_fetcher.rb
"lib/bundler/gemdeps.rb", lib/bundler/gem_tasks.rb
"lib/bundler/graph.rb", lib/bundler/gem_version_promoter.rb
"lib/bundler/index.rb", lib/bundler/gemdeps.rb
"lib/bundler/injector.rb", lib/bundler/graph.rb
"lib/bundler/inline.rb", lib/bundler/index.rb
"lib/bundler/installer.rb", lib/bundler/injector.rb
"lib/bundler/installer/gem_installer.rb", lib/bundler/inline.rb
"lib/bundler/installer/parallel_installer.rb", lib/bundler/installer.rb
"lib/bundler/installer/standalone.rb", lib/bundler/installer/gem_installer.rb
"lib/bundler/lazy_specification.rb", lib/bundler/installer/parallel_installer.rb
"lib/bundler/lockfile_parser.rb", lib/bundler/installer/standalone.rb
"lib/bundler/match_platform.rb", lib/bundler/lazy_specification.rb
"lib/bundler/mirror.rb", lib/bundler/lockfile_generator.rb
"lib/bundler/plugin.rb", lib/bundler/lockfile_parser.rb
"lib/bundler/plugin/api.rb", lib/bundler/match_platform.rb
"lib/bundler/plugin/api/source.rb", lib/bundler/mirror.rb
"lib/bundler/plugin/dsl.rb", lib/bundler/plugin.rb
"lib/bundler/plugin/index.rb", lib/bundler/plugin/api.rb
"lib/bundler/plugin/installer.rb", lib/bundler/plugin/api/source.rb
"lib/bundler/plugin/installer/git.rb", lib/bundler/plugin/dsl.rb
"lib/bundler/plugin/installer/rubygems.rb", lib/bundler/plugin/index.rb
"lib/bundler/plugin/source_list.rb", lib/bundler/plugin/installer.rb
"lib/bundler/psyched_yaml.rb", lib/bundler/plugin/installer/git.rb
"lib/bundler/remote_specification.rb", lib/bundler/plugin/installer/rubygems.rb
"lib/bundler/resolver.rb", lib/bundler/plugin/source_list.rb
"lib/bundler/retry.rb", lib/bundler/process_lock.rb
"lib/bundler/ruby_dsl.rb", lib/bundler/psyched_yaml.rb
"lib/bundler/ruby_version.rb", lib/bundler/remote_specification.rb
"lib/bundler/rubygems_ext.rb", lib/bundler/resolver.rb
"lib/bundler/rubygems_gem_installer.rb", lib/bundler/resolver/spec_group.rb
"lib/bundler/rubygems_integration.rb", lib/bundler/retry.rb
"lib/bundler/runtime.rb", lib/bundler/ruby_dsl.rb
"lib/bundler/settings.rb", lib/bundler/ruby_version.rb
"lib/bundler/setup.rb", lib/bundler/rubygems_ext.rb
"lib/bundler/shared_helpers.rb", lib/bundler/rubygems_gem_installer.rb
"lib/bundler/similarity_detector.rb", lib/bundler/rubygems_integration.rb
"lib/bundler/source.rb", lib/bundler/runtime.rb
"lib/bundler/source/gemspec.rb", lib/bundler/settings.rb
"lib/bundler/source/git.rb", lib/bundler/settings/validator.rb
"lib/bundler/source/git/git_proxy.rb", lib/bundler/setup.rb
"lib/bundler/source/path.rb", lib/bundler/shared_helpers.rb
"lib/bundler/source/path/installer.rb", lib/bundler/similarity_detector.rb
"lib/bundler/source/rubygems.rb", lib/bundler/source.rb
"lib/bundler/source/rubygems/remote.rb", lib/bundler/source/gemspec.rb
"lib/bundler/source_list.rb", lib/bundler/source/git.rb
"lib/bundler/spec_set.rb", lib/bundler/source/git/git_proxy.rb
"lib/bundler/ssl_certs/.document", lib/bundler/source/metadata.rb
"lib/bundler/ssl_certs/certificate_manager.rb", lib/bundler/source/path.rb
"lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem", lib/bundler/source/path/installer.rb
"lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem", lib/bundler/source/rubygems.rb
"lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem", lib/bundler/source/rubygems/remote.rb
"lib/bundler/stub_specification.rb", lib/bundler/source_list.rb
"lib/bundler/templates/Executable", lib/bundler/spec_set.rb
"lib/bundler/templates/Executable.standalone", lib/bundler/ssl_certs/.document
"lib/bundler/templates/Gemfile", lib/bundler/ssl_certs/certificate_manager.rb
"lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt", lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem
"lib/bundler/templates/newgem/Gemfile.tt", lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem
"lib/bundler/templates/newgem/LICENSE.txt.tt", lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem
"lib/bundler/templates/newgem/README.md.tt", lib/bundler/stub_specification.rb
"lib/bundler/templates/newgem/Rakefile.tt", lib/bundler/templates/Executable
"lib/bundler/templates/newgem/bin/console.tt", lib/bundler/templates/Executable.bundler
"lib/bundler/templates/newgem/bin/setup.tt", lib/bundler/templates/Executable.standalone
"lib/bundler/templates/newgem/exe/newgem.tt", lib/bundler/templates/Gemfile
"lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt", lib/bundler/templates/gems.rb
"lib/bundler/templates/newgem/ext/newgem/newgem.c.tt", lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
"lib/bundler/templates/newgem/ext/newgem/newgem.h.tt", lib/bundler/templates/newgem/Gemfile.tt
"lib/bundler/templates/newgem/gitignore.tt", lib/bundler/templates/newgem/LICENSE.txt.tt
"lib/bundler/templates/newgem/lib/newgem.rb.tt", lib/bundler/templates/newgem/README.md.tt
"lib/bundler/templates/newgem/lib/newgem/version.rb.tt", lib/bundler/templates/newgem/Rakefile.tt
"lib/bundler/templates/newgem/newgem.gemspec.tt", lib/bundler/templates/newgem/bin/console.tt
"lib/bundler/templates/newgem/rspec.tt", lib/bundler/templates/newgem/bin/setup.tt
"lib/bundler/templates/newgem/spec/newgem_spec.rb.tt", lib/bundler/templates/newgem/exe/newgem.tt
"lib/bundler/templates/newgem/spec/spec_helper.rb.tt", lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt
"lib/bundler/templates/newgem/test/newgem_test.rb.tt", lib/bundler/templates/newgem/ext/newgem/newgem.c.tt
"lib/bundler/templates/newgem/test/test_helper.rb.tt", lib/bundler/templates/newgem/ext/newgem/newgem.h.tt
"lib/bundler/templates/newgem/travis.yml.tt", lib/bundler/templates/newgem/gitignore.tt
"lib/bundler/ui.rb", lib/bundler/templates/newgem/lib/newgem.rb.tt
"lib/bundler/ui/rg_proxy.rb", lib/bundler/templates/newgem/lib/newgem/version.rb.tt
"lib/bundler/ui/shell.rb", lib/bundler/templates/newgem/newgem.gemspec.tt
"lib/bundler/ui/silent.rb", lib/bundler/templates/newgem/rspec.tt
"lib/bundler/uri_credentials_filter.rb", lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
"lib/bundler/vendor/molinillo/lib/molinillo.rb", lib/bundler/templates/newgem/spec/spec_helper.rb.tt
"lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb", lib/bundler/templates/newgem/test/newgem_test.rb.tt
"lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb", lib/bundler/templates/newgem/test/test_helper.rb.tt
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb", lib/bundler/templates/newgem/travis.yml.tt
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb", lib/bundler/ui.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb", lib/bundler/ui/rg_proxy.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb", lib/bundler/ui/shell.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb", lib/bundler/ui/silent.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb", lib/bundler/uri_credentials_filter.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb", lib/bundler/vendor/fileutils/lib/fileutils.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb", lib/bundler/vendor/molinillo/lib/molinillo.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb", lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb
"lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb", lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
"lib/bundler/vendor/molinillo/lib/molinillo/errors.rb", lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
"lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
"lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
"lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
"lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
"lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
"lib/bundler/vendor/molinillo/lib/molinillo/state.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
"lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
"lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
"lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
"lib/bundler/vendor/thor/lib/thor.rb", lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
"lib/bundler/vendor/thor/lib/thor/actions.rb", lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
"lib/bundler/vendor/thor/lib/thor/actions/create_file.rb", lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
"lib/bundler/vendor/thor/lib/thor/actions/create_link.rb", lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
"lib/bundler/vendor/thor/lib/thor/actions/directory.rb", lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb
"lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb", lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
"lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb", lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb
"lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb", lib/bundler/vendor/molinillo/lib/molinillo/state.rb
"lib/bundler/vendor/thor/lib/thor/base.rb", lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb
"lib/bundler/vendor/thor/lib/thor/command.rb", lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
"lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb", lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb
"lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb", lib/bundler/vendor/thor/lib/thor.rb
"lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb", lib/bundler/vendor/thor/lib/thor/actions.rb
"lib/bundler/vendor/thor/lib/thor/error.rb", lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
"lib/bundler/vendor/thor/lib/thor/group.rb", lib/bundler/vendor/thor/lib/thor/actions/create_link.rb
"lib/bundler/vendor/thor/lib/thor/invocation.rb", lib/bundler/vendor/thor/lib/thor/actions/directory.rb
"lib/bundler/vendor/thor/lib/thor/line_editor.rb", lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
"lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb", lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
"lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb", lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
"lib/bundler/vendor/thor/lib/thor/parser.rb", lib/bundler/vendor/thor/lib/thor/base.rb
"lib/bundler/vendor/thor/lib/thor/parser/argument.rb", lib/bundler/vendor/thor/lib/thor/command.rb
"lib/bundler/vendor/thor/lib/thor/parser/arguments.rb", lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
"lib/bundler/vendor/thor/lib/thor/parser/option.rb", lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb
"lib/bundler/vendor/thor/lib/thor/parser/options.rb", lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb
"lib/bundler/vendor/thor/lib/thor/rake_compat.rb", lib/bundler/vendor/thor/lib/thor/error.rb
"lib/bundler/vendor/thor/lib/thor/runner.rb", lib/bundler/vendor/thor/lib/thor/group.rb
"lib/bundler/vendor/thor/lib/thor/shell.rb", lib/bundler/vendor/thor/lib/thor/invocation.rb
"lib/bundler/vendor/thor/lib/thor/shell/basic.rb", lib/bundler/vendor/thor/lib/thor/line_editor.rb
"lib/bundler/vendor/thor/lib/thor/shell/color.rb", lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb
"lib/bundler/vendor/thor/lib/thor/shell/html.rb", lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb
"lib/bundler/vendor/thor/lib/thor/util.rb", lib/bundler/vendor/thor/lib/thor/parser.rb
"lib/bundler/vendor/thor/lib/thor/version.rb", lib/bundler/vendor/thor/lib/thor/parser/argument.rb
"lib/bundler/vendored_molinillo.rb", lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
"lib/bundler/vendored_persistent.rb", lib/bundler/vendor/thor/lib/thor/parser/option.rb
"lib/bundler/vendored_thor.rb", lib/bundler/vendor/thor/lib/thor/parser/options.rb
"lib/bundler/version.rb", lib/bundler/vendor/thor/lib/thor/rake_compat.rb
"lib/bundler/version_ranges.rb", lib/bundler/vendor/thor/lib/thor/runner.rb
"lib/bundler/vlad.rb", lib/bundler/vendor/thor/lib/thor/shell.rb
"lib/bundler/worker.rb", lib/bundler/vendor/thor/lib/thor/shell/basic.rb
"lib/bundler/yaml_serializer.rb" lib/bundler/vendor/thor/lib/thor/shell/color.rb
lib/bundler/vendor/thor/lib/thor/shell/html.rb
lib/bundler/vendor/thor/lib/thor/util.rb
lib/bundler/vendor/thor/lib/thor/version.rb
lib/bundler/vendored_fileutils.rb
lib/bundler/vendored_molinillo.rb
lib/bundler/vendored_persistent.rb
lib/bundler/vendored_thor.rb
lib/bundler/version.rb
lib/bundler/version_ranges.rb
lib/bundler/vlad.rb
lib/bundler/worker.rb
lib/bundler/yaml_serializer.rb
man/bundle-platform.1
man/bundle-update.1
man/bundle-init.1.txt
man/bundle-info.ronn
man/bundle-gem.ronn
man/bundle-add.1.txt
man/bundle-list.ronn
man/bundle-info.1
man/bundle-init.1
man/bundle-outdated.ronn
man/bundle-init.ronn
man/bundle.1
man/bundle-show.1.txt
man/bundle-exec.1
man/bundle-install.1.txt
man/bundle-binstubs.1.txt
man/bundle-open.1.txt
man/index.txt
man/bundle-pristine.ronn
man/bundle-install.1
man/bundle-inject.ronn
man/bundle-list.1
man/bundle-outdated.1.txt
man/bundle-list.1.txt
man/bundle-update.ronn
man/bundle-clean.1.txt
man/bundle-show.ronn
man/bundle-pristine.1.txt
man/bundle-outdated.1
man/bundle-check.1
man/bundle-show.1
man/gemfile.5
man/bundle-gem.1
man/bundle-install.ronn
man/bundle-gem.1.txt
man/bundle-open.1
man/bundle-add.ronn
man/bundle-lock.1.txt
man/bundle-open.ronn
man/bundle-lock.1
man/bundle-exec.ronn
man/bundle-check.ronn
man/bundle-info.1.txt
man/bundle-lock.ronn
man/bundle-pristine.1
man/bundle-viz.1.txt
man/bundle.ronn
man/bundle-platform.ronn
man/bundle-binstubs.ronn
man/bundle-exec.1.txt
man/bundle.1.txt
man/bundle-config.1.txt
man/bundle-package.1.txt
man/bundle-platform.1.txt
man/bundle-binstubs.1
man/bundle-viz.1
man/bundle-clean.ronn
man/bundle-package.1
man/bundle-add.1
man/bundle-config.1
man/bundle-package.ronn
man/bundle-viz.ronn
man/bundle-check.1.txt
man/bundle-clean.1
man/gemfile.5.txt
man/bundle-inject.1
man/gemfile.5.ronn
man/bundle-config.ronn
man/bundle-inject.1.txt
man/bundle-update.1.txt
CHANGELOG.md
LICENSE.md
README.md
] ]
s.bindir = "exe" s.bindir = "exe"
s.executables = %w(bundle bundler) s.executables = %w[bundle bundler]
s.require_paths = ["lib"] s.require_paths = ["lib"]
end end

View file

@ -1,9 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
require "fileutils"
require "bundler/compatibility_guard"
require "bundler/vendored_fileutils"
require "pathname" require "pathname"
require "rbconfig" require "rbconfig"
require "thread" require "thread"
require "tmpdir"
require "bundler/errors" require "bundler/errors"
require "bundler/environment_preserver" require "bundler/environment_preserver"
@ -13,9 +15,10 @@ require "bundler/rubygems_integration"
require "bundler/version" require "bundler/version"
require "bundler/constants" require "bundler/constants"
require "bundler/current_ruby" require "bundler/current_ruby"
require "bundler/build_metadata"
module Bundler module Bundler
environment_preserver = EnvironmentPreserver.new(ENV, %w(PATH GEM_PATH)) environment_preserver = EnvironmentPreserver.new(ENV, EnvironmentPreserver::BUNDLER_KEYS)
ORIGINAL_ENV = environment_preserver.restore ORIGINAL_ENV = environment_preserver.restore
ENV.replace(environment_preserver.backup) ENV.replace(environment_preserver.backup)
SUDO_MUTEX = Mutex.new SUDO_MUTEX = Mutex.new
@ -40,6 +43,7 @@ module Bundler
autoload :LazySpecification, "bundler/lazy_specification" autoload :LazySpecification, "bundler/lazy_specification"
autoload :LockfileParser, "bundler/lockfile_parser" autoload :LockfileParser, "bundler/lockfile_parser"
autoload :MatchPlatform, "bundler/match_platform" autoload :MatchPlatform, "bundler/match_platform"
autoload :ProcessLock, "bundler/process_lock"
autoload :RemoteSpecification, "bundler/remote_specification" autoload :RemoteSpecification, "bundler/remote_specification"
autoload :Resolver, "bundler/resolver" autoload :Resolver, "bundler/resolver"
autoload :Retry, "bundler/retry" autoload :Retry, "bundler/retry"
@ -58,8 +62,6 @@ module Bundler
autoload :VersionRanges, "bundler/version_ranges" autoload :VersionRanges, "bundler/version_ranges"
class << self class << self
attr_writer :bundle_path
def configure def configure
@configured ||= configure_gem_home_and_path @configured ||= configure_gem_home_and_path
end end
@ -75,7 +77,11 @@ module Bundler
# Returns absolute path of where gems are installed on the filesystem. # Returns absolute path of where gems are installed on the filesystem.
def bundle_path def bundle_path
@bundle_path ||= Pathname.new(settings.path).expand_path(root) @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root)
end
def configured_bundle_path
@configured_bundle_path ||= settings.path.tap(&:validate!)
end end
# Returns absolute location of where binstubs are installed to. # Returns absolute location of where binstubs are installed to.
@ -113,7 +119,7 @@ module Bundler
end end
def environment def environment
SharedHelpers.major_deprecation "Bundler.environment has been removed in favor of Bundler.load" SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load"
load load
end end
@ -130,6 +136,12 @@ module Bundler
end end
end end
def frozen?
frozen = settings[:deployment]
frozen ||= settings[:frozen] unless feature_flag.deployment_means_frozen?
frozen
end
def locked_gems def locked_gems
@locked_gems ||= @locked_gems ||=
if defined?(@definition) && @definition if defined?(@definition) && @definition
@ -168,6 +180,7 @@ module Bundler
def tmp_home_path(login, warning) def tmp_home_path(login, warning)
login ||= "unknown" login ||= "unknown"
Kernel.send(:require, "tmpdir")
path = Pathname.new(Dir.tmpdir).join("bundler", "home") path = Pathname.new(Dir.tmpdir).join("bundler", "home")
SharedHelpers.filesystem_access(path) do |tmp_home_path| SharedHelpers.filesystem_access(path) do |tmp_home_path|
unless tmp_home_path.exist? unless tmp_home_path.exist?
@ -196,17 +209,13 @@ module Bundler
bundle_path.join("specifications") bundle_path.join("specifications")
end end
def cache
bundle_path.join("cache/bundler")
end
def user_cache def user_cache
user_bundle_path.join("cache") user_bundle_path.join("cache")
end end
def root def root
@root ||= begin @root ||= begin
default_gemfile.dirname.expand_path SharedHelpers.root
rescue GemfileNotFound rescue GemfileNotFound
bundle_dir = default_bundle_dir bundle_dir = default_bundle_dir
raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir
@ -215,8 +224,8 @@ module Bundler
end end
def app_config_path def app_config_path
if ENV["BUNDLE_APP_CONFIG"] if app_config = ENV["BUNDLE_APP_CONFIG"]
Pathname.new(ENV["BUNDLE_APP_CONFIG"]).expand_path(root) Pathname.new(app_config).expand_path(root)
else else
root.join(".bundle") root.join(".bundle")
end end
@ -224,10 +233,11 @@ module Bundler
def app_cache(custom_path = nil) def app_cache(custom_path = nil)
path = custom_path || root path = custom_path || root
path.join(settings.app_cache_path) Pathname.new(path).join(settings.app_cache_path)
end end
def tmp(name = Process.pid.to_s) def tmp(name = Process.pid.to_s)
Kernel.send(:require, "tmpdir")
Pathname.new(Dir.mktmpdir(["bundler", name])) Pathname.new(Dir.mktmpdir(["bundler", name]))
end end
@ -257,7 +267,7 @@ EOF
# @deprecated Use `original_env` instead # @deprecated Use `original_env` instead
# @return [Hash] Environment with all bundler-related variables removed # @return [Hash] Environment with all bundler-related variables removed
def clean_env def clean_env
Bundler::SharedHelpers.major_deprecation("`Bundler.clean_env` has weird edge cases, use `.original_env` instead") Bundler::SharedHelpers.major_deprecation(2, "`Bundler.clean_env` has weird edge cases, use `.original_env` instead")
env = original_env env = original_env
if env.key?("BUNDLER_ORIG_MANPATH") if env.key?("BUNDLER_ORIG_MANPATH")
@ -313,21 +323,25 @@ EOF
end end
def system_bindir def system_bindir
# Gem.bindir doesn't always return the location that Rubygems will install # Gem.bindir doesn't always return the location that RubyGems will install
# system binaries. If you put '-n foo' in your .gemrc, Rubygems will # system binaries. If you put '-n foo' in your .gemrc, RubyGems will
# install binstubs there instead. Unfortunately, Rubygems doesn't expose # install binstubs there instead. Unfortunately, RubyGems doesn't expose
# that directory at all, so rather than parse .gemrc ourselves, we allow # that directory at all, so rather than parse .gemrc ourselves, we allow
# the directory to be set as well, via `bundle config bindir foo`. # the directory to be set as well, via `bundle config bindir foo`.
Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir
end end
def use_system_gems?
configured_bundle_path.use_system_gems?
end
def requires_sudo? def requires_sudo?
return @requires_sudo if defined?(@requires_sudo_ran) return @requires_sudo if defined?(@requires_sudo_ran)
sudo_present = which "sudo" if settings.allow_sudo? sudo_present = which "sudo" if settings.allow_sudo?
if sudo_present if sudo_present
# the bundle path and subdirectories need to be writable for Rubygems # the bundle path and subdirectories need to be writable for RubyGems
# to be able to unpack and install gems without exploding # to be able to unpack and install gems without exploding
path = bundle_path path = bundle_path
path = path.parent until path.exist? path = path.parent until path.exist?
@ -449,14 +463,17 @@ EOF
end end
def reset_paths! def reset_paths!
@root = nil @bin_path = nil
@settings = nil @bundler_major_version = nil
@bundle_path = nil
@configured = nil
@configured_bundle_path = nil
@definition = nil @definition = nil
@setup = nil
@load = nil @load = nil
@locked_gems = nil @locked_gems = nil
@bundle_path = nil @root = nil
@bin_path = nil @settings = nil
@setup = nil
@user_home = nil @user_home = nil
end end
@ -470,6 +487,8 @@ EOF
private private
def eval_yaml_gemspec(path, contents) def eval_yaml_gemspec(path, contents)
Kernel.send(:require, "bundler/psyched_yaml")
# If the YAML is invalid, Syck raises an ArgumentError, and Psych # If the YAML is invalid, Syck raises an ArgumentError, and Psych
# raises a Psych::SyntaxError. See psyched_yaml.rb for more info. # raises a Psych::SyntaxError. See psyched_yaml.rb for more info.
Gem::Specification.from_yaml(contents) Gem::Specification.from_yaml(contents)
@ -478,7 +497,7 @@ EOF
end end
def eval_gemspec(path, contents) def eval_gemspec(path, contents)
eval(contents, TOPLEVEL_BINDING, path.expand_path.to_s) eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s)
rescue ScriptError, StandardError => e rescue ScriptError, StandardError => e
msg = "There was an error while loading `#{path.basename}`: #{e.message}" msg = "There was an error while loading `#{path.basename}`: #{e.message}"
@ -495,14 +514,14 @@ EOF
bundle_path bundle_path
end end
def configure_gem_path(env = ENV, settings = self.settings) def configure_gem_path(env = ENV)
blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty? blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty?
if settings[:disable_shared_gems] if !use_system_gems?
# this needs to be empty string to cause # this needs to be empty string to cause
# PathSupport.split_gem_path to only load up the # PathSupport.split_gem_path to only load up the
# Bundler --path setting as the GEM_PATH. # Bundler --path setting as the GEM_PATH.
env["GEM_PATH"] = "" env["GEM_PATH"] = ""
elsif blank_home || Bundler.rubygems.gem_dir != bundle_path.to_s elsif blank_home
possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path] possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path]
paths = possibles.flatten.compact.uniq.reject(&:empty?) paths = possibles.flatten.compact.uniq.reject(&:empty?)
env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR) env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR)
@ -510,14 +529,7 @@ EOF
end end
def configure_gem_home def configure_gem_home
# TODO: This mkdir_p is only needed for JRuby <= 1.5 and should go away (GH #602) Bundler::SharedHelpers.set_env "GEM_HOME", File.expand_path(bundle_path, root)
begin
FileUtils.mkdir_p bundle_path.to_s
rescue
nil
end
ENV["GEM_HOME"] = File.expand_path(bundle_path, root)
Bundler.rubygems.clear_paths Bundler.rubygems.clear_paths
end end

View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Bundler
# Represents metadata from when the Bundler gem was built.
module BuildMetadata
# begin ivars
@release = false
# end ivars
# A hash representation of the build metadata.
def self.to_h
{
"Built At" => built_at,
"Git SHA" => git_commit_sha,
"Released Version" => release?,
}
end
# A string representing the date the bundler gem was built.
def self.built_at
@built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze
end
# The SHA for the git commit the bundler gem was built from.
def self.git_commit_sha
@git_commit_sha ||= Dir.chdir(File.expand_path("..", __FILE__)) do
`git rev-parse --short HEAD`.strip.freeze
end
end
# Whether this is an official release build of Bundler.
def self.release?
@release
end
end
end

View file

@ -1,4 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/shared_helpers"
Bundler::SharedHelpers.major_deprecation 2,
"The Bundler task for Capistrano. Please use http://github.com/capistrano/bundler"
# Capistrano task for Bundler. # Capistrano task for Bundler.
# #
# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and # Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and

View file

@ -1,13 +1,18 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler" require "bundler"
require "bundler/vendored_thor" require "bundler/vendored_thor"
module Bundler module Bundler
class CLI < Thor class CLI < Thor
AUTO_INSTALL_CMDS = %w(show binstubs outdated exec open console licenses clean).freeze require "bundler/cli/common"
PARSEABLE_COMMANDS = %w(
package_name "Bundler"
AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze
PARSEABLE_COMMANDS = %w[
check config help exec platform show version check config help exec platform show version
).freeze ].freeze
def self.start(*) def self.start(*)
super super
@ -30,11 +35,11 @@ module Bundler
custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile]
if custom_gemfile && !custom_gemfile.empty? if custom_gemfile && !custom_gemfile.empty?
ENV["BUNDLE_GEMFILE"] = File.expand_path(custom_gemfile) Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile)
Bundler.reset_paths! Bundler.reset_paths!
end end
Bundler.settings[:retry] = options[:retry] if options[:retry] Bundler.settings.set_command_option_if_given :retry, options[:retry]
current_cmd = args.last[:current_command].name current_cmd = args.last[:current_command].name
auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
@ -42,7 +47,6 @@ module Bundler
raise InvalidOption, e.message raise InvalidOption, e.message
ensure ensure
self.options ||= {} self.options ||= {}
Bundler.settings.cli_flags_given = !options.empty?
unprinted_warnings = Bundler.ui.unprinted_warnings unprinted_warnings = Bundler.ui.unprinted_warnings
Bundler.ui = UI::Shell.new(options) Bundler.ui = UI::Shell.new(options)
Bundler.ui.level = "debug" if options["verbose"] Bundler.ui.level = "debug" if options["verbose"]
@ -57,10 +61,41 @@ module Bundler
end end
end end
def self.deprecated_option(*args, &blk)
return if Bundler.feature_flag.forget_cli_options?
method_option(*args, &blk)
end
check_unknown_options!(:except => [:config, :exec]) check_unknown_options!(:except => [:config, :exec])
stop_on_unknown_option! :exec stop_on_unknown_option! :exec
default_task :install desc "cli_help", "Prints a summary of bundler commands", :hide => true
def cli_help
version
Bundler.ui.info "\n"
primary_commands = ["install", "update",
Bundler.feature_flag.cache_command_is_package? ? "cache" : "package",
"exec", "config", "help"]
list = self.class.printable_commands(true)
by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] }
utilities = by_name.keys.sort - primary_commands
primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first }
utilities.map! {|name| by_name[name].first }
shell.say "Bundler commands:\n\n"
shell.say " Primary commands:\n"
shell.print_table(primary_commands, :indent => 4, :truncate => true)
shell.say
shell.say " Utilities:\n"
shell.print_table(utilities, :indent => 4, :truncate => true)
shell.say
self.class.send(:class_options_help, shell)
end
default_task(Bundler.feature_flag.default_cli_command)
class_option "no-color", :type => :boolean, :desc => "Disable colorization in output" class_option "no-color", :type => :boolean, :desc => "Disable colorization in output"
class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM", class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM",
:desc => "Specify the number of times you wish to attempt network commands" :desc => "Specify the number of times you wish to attempt network commands"
@ -107,7 +142,7 @@ module Bundler
Gemfile to a gem with a gemspec, the --gemspec option will automatically add each Gemfile to a gem with a gemspec, the --gemspec option will automatically add each
dependency listed in the gemspec file to the newly created Gemfile. dependency listed in the gemspec file to the newly created Gemfile.
D D
method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" deprecated_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile"
def init def init
require "bundler/cli/init" require "bundler/cli/init"
Init.new(options.dup).run Init.new(options.dup).run
@ -124,7 +159,7 @@ module Bundler
method_option "gemfile", :type => :string, :banner => method_option "gemfile", :type => :string, :banner =>
"Use the specified gemfile instead of Gemfile" "Use the specified gemfile instead of Gemfile"
method_option "path", :type => :string, :banner => method_option "path", :type => :string, :banner =>
"Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on this machine" "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
map "c" => "check" map "c" => "check"
def check def check
require "bundler/cli/check" require "bundler/cli/check"
@ -142,13 +177,13 @@ module Bundler
If the bundle has already been installed, bundler will tell you so and then exit. If the bundle has already been installed, bundler will tell you so and then exit.
D D
method_option "binstubs", :type => :string, :lazy_default => "bin", :banner => deprecated_option "binstubs", :type => :string, :lazy_default => "bin", :banner =>
"Generate bin stubs for bundled gems to ./bin" "Generate bin stubs for bundled gems to ./bin"
method_option "clean", :type => :boolean, :banner => deprecated_option "clean", :type => :boolean, :banner =>
"Run bundle clean automatically after install" "Run bundle clean automatically after install"
method_option "deployment", :type => :boolean, :banner => deprecated_option "deployment", :type => :boolean, :banner =>
"Install using defaults tuned for deployment environments" "Install using defaults tuned for deployment environments"
method_option "frozen", :type => :boolean, :banner => deprecated_option "frozen", :type => :boolean, :banner =>
"Do not allow the Gemfile.lock to be updated after this install" "Do not allow the Gemfile.lock to be updated after this install"
method_option "full-index", :type => :boolean, :banner => method_option "full-index", :type => :boolean, :banner =>
"Fall back to using the single-file index of all gems" "Fall back to using the single-file index of all gems"
@ -158,28 +193,29 @@ module Bundler
"Specify the number of jobs to run in parallel" "Specify the number of jobs to run in parallel"
method_option "local", :type => :boolean, :banner => method_option "local", :type => :boolean, :banner =>
"Do not attempt to fetch gems remotely and use the gem cache instead" "Do not attempt to fetch gems remotely and use the gem cache instead"
method_option "no-cache", :type => :boolean, :banner => deprecated_option "no-cache", :type => :boolean, :banner =>
"Don't update the existing gem cache." "Don't update the existing gem cache."
method_option "force", :type => :boolean, :banner => method_option "redownload", :type => :boolean, :aliases =>
[Bundler.feature_flag.forget_cli_options? ? nil : "--force"].compact, :banner =>
"Force downloading every gem." "Force downloading every gem."
method_option "no-prune", :type => :boolean, :banner => deprecated_option "no-prune", :type => :boolean, :banner =>
"Don't remove stale gems from the cache." "Don't remove stale gems from the cache."
method_option "path", :type => :string, :banner => deprecated_option "path", :type => :string, :banner =>
"Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on this machine" "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on this machine"
method_option "quiet", :type => :boolean, :banner => method_option "quiet", :type => :boolean, :banner =>
"Only output warnings and errors." "Only output warnings and errors."
method_option "shebang", :type => :string, :banner => deprecated_option "shebang", :type => :string, :banner =>
"Specify a different shebang executable name than the default (usually 'ruby')" "Specify a different shebang executable name than the default (usually 'ruby')"
method_option "standalone", :type => :array, :lazy_default => [], :banner => method_option "standalone", :type => :array, :lazy_default => [], :banner =>
"Make a bundle that can work without the Bundler runtime" "Make a bundle that can work without the Bundler runtime"
method_option "system", :type => :boolean, :banner => deprecated_option "system", :type => :boolean, :banner =>
"Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application"
method_option "trust-policy", :alias => "P", :type => :string, :banner => method_option "trust-policy", :alias => "P", :type => :string, :banner =>
"Gem trust policy (like gem install -P). Must be one of " + "Gem trust policy (like gem install -P). Must be one of " +
Bundler.rubygems.security_policy_keys.join("|") Bundler.rubygems.security_policy_keys.join("|")
method_option "without", :type => :array, :banner => deprecated_option "without", :type => :array, :banner =>
"Exclude gems that are part of the specified named group." "Exclude gems that are part of the specified named group."
method_option "with", :type => :array, :banner => deprecated_option "with", :type => :array, :banner =>
"Include gems that are part of the specified named group." "Include gems that are part of the specified named group."
map "i" => "install" map "i" => "install"
def install def install
@ -189,7 +225,7 @@ module Bundler
end end
end end
desc "update [OPTIONS]", "update the current environment" desc "update [OPTIONS]", "Update the current environment"
long_desc <<-D long_desc <<-D
Update will install the newest versions of the gems listed in the Gemfile. Use Update will install the newest versions of the gems listed in the Gemfile. Use
update when you have changed the Gemfile, or if you want to get the newest update when you have changed the Gemfile, or if you want to get the newest
@ -223,6 +259,8 @@ module Bundler
"Do not allow any gem to be updated past latest --patch | --minor | --major" "Do not allow any gem to be updated past latest --patch | --minor | --major"
method_option "conservative", :type => :boolean, :banner => method_option "conservative", :type => :boolean, :banner =>
"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 shared dependencies to be updated."
method_option "all", :type => :boolean, :banner =>
"Update everything."
def update(*gems) def update(*gems)
require "bundler/cli/update" require "bundler/cli/update"
Update.new(options, gems).run Update.new(options, gems).run
@ -238,12 +276,24 @@ module Bundler
method_option "outdated", :type => :boolean, method_option "outdated", :type => :boolean,
:banner => "Show verbose output including whether gems are outdated." :banner => "Show verbose output including whether gems are outdated."
def show(gem_name = nil) def show(gem_name = nil)
Bundler::SharedHelpers.major_deprecation("use `bundle show` instead of `bundle list`") if ARGV[0] == "list" Bundler::SharedHelpers.major_deprecation(2, "use `bundle list` instead of `bundle show`") if ARGV[0] == "show"
require "bundler/cli/show" require "bundler/cli/show"
Show.new(options, gem_name).run Show.new(options, gem_name).run
end end
# TODO: 2.0 remove `bundle list` # TODO: 2.0 remove `bundle show`
map %w(list) => "show"
if Bundler.feature_flag.list_command?
desc "list", "List all gems in the bundle"
method_option "name-only", :type => :boolean, :banner => "print only the gem names"
def list
require "bundler/cli/list"
List.new(options).run
end
map %w[ls] => "list"
else
map %w[list] => "show"
end
desc "info GEM [OPTIONS]", "Show information for the given gem" desc "info GEM [OPTIONS]", "Show information for the given gem"
method_option "path", :type => :boolean, :banner => "Print full path to gem" method_option "path", :type => :boolean, :banner => "Print full path to gem"
@ -262,6 +312,8 @@ module Bundler
"Overwrite existing binstubs if they exist" "Overwrite existing binstubs if they exist"
method_option "path", :type => :string, :lazy_default => "bin", :banner => method_option "path", :type => :string, :lazy_default => "bin", :banner =>
"Binstub destination directory (default bin)" "Binstub destination directory (default bin)"
method_option "shebang", :type => :string, :banner =>
"Specify a different shebang executable name than the default (usually 'ruby')"
method_option "standalone", :type => :boolean, :banner => method_option "standalone", :type => :boolean, :banner =>
"Make binstubs that can work without the Bundler runtime" "Make binstubs that can work without the Bundler runtime"
def binstubs(*gems) def binstubs(*gems)
@ -282,7 +334,7 @@ module Bundler
Add.new(options.dup, gem_name).run Add.new(options.dup, gem_name).run
end end
desc "outdated GEM [OPTIONS]", "list installed gems with newer versions available" desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available"
long_desc <<-D long_desc <<-D
Outdated lists the names and versions of gems that have a newer version available Outdated lists the names and versions of gems that have a newer version available
in the given source. Calling outdated with [GEM [GEM]] will only check for newer in the given source. Calling outdated with [GEM [GEM]] will only check for newer
@ -292,8 +344,8 @@ module Bundler
For more information on patch level options (--major, --minor, --patch, For more information on patch level options (--major, --minor, --patch,
--update-strict) see documentation on the same options on the update command. --update-strict) see documentation on the same options on the update command.
D D
method_option "group", :aliases => "--group", :type => :string, :banner => "List gems from a specific group" method_option "group", :type => :string, :banner => "List gems from a specific group"
method_option "groups", :aliases => "--groups", :type => :boolean, :banner => "List gems organized by groups" method_option "groups", :type => :boolean, :banner => "List gems organized by groups"
method_option "local", :type => :boolean, :banner => method_option "local", :type => :boolean, :banner =>
"Do not attempt to fetch gems remotely and use the gem cache instead" "Do not attempt to fetch gems remotely and use the gem cache instead"
method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems"
@ -315,17 +367,27 @@ module Bundler
Outdated.new(options, gems).run Outdated.new(options, gems).run
end end
if Bundler.feature_flag.cache_command_is_package?
map %w[cache] => :package
else
desc "cache [OPTIONS]", "Cache all the gems to vendor/cache", :hide => true desc "cache [OPTIONS]", "Cache all the gems to vendor/cache", :hide => true
method_option "all", :type => :boolean, :banner => "Include all sources (including path and git)." unless Bundler.feature_flag.cache_command_is_package?
method_option "all", :type => :boolean,
:banner => "Include all sources (including path and git)."
end
method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one"
method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
def cache def cache
require "bundler/cli/cache" require "bundler/cli/cache"
Cache.new(options).run Cache.new(options).run
end end
end
desc "package [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" desc "#{Bundler.feature_flag.cache_command_is_package? ? :cache : :package} [OPTIONS]", "Locks and then caches all of the gems into vendor/cache"
method_option "all", :type => :boolean, :banner => "Include all sources (including path and git)." unless Bundler.feature_flag.cache_command_is_package?
method_option "all", :type => :boolean,
:banner => "Include all sources (including path and git)."
end
method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one"
method_option "cache-path", :type => :string, :banner => method_option "cache-path", :type => :string, :banner =>
"Specify a different cache path than the default (vendor/cache)." "Specify a different cache path than the default (vendor/cache)."
@ -347,14 +409,14 @@ module Bundler
require "bundler/cli/package" require "bundler/cli/package"
Package.new(options).run Package.new(options).run
end end
map %w(pack) => :package map %w[pack] => :package
desc "exec [OPTIONS]", "Run the command in context of the bundle" desc "exec [OPTIONS]", "Run the command in context of the bundle"
method_option :keep_file_descriptors, :type => :boolean, :default => false method_option :keep_file_descriptors, :type => :boolean, :default => false
long_desc <<-D long_desc <<-D
Exec runs a command, providing it access to the gems in the bundle. While using Exec runs a command, providing it access to the gems in the bundle. While using
bundle exec you can require and call the bundled gems as if they were installed bundle exec you can require and call the bundled gems as if they were installed
into the system wide Rubygems repository. into the system wide RubyGems repository.
D D
map "e" => "exec" map "e" => "exec"
def exec(*args) def exec(*args)
@ -362,7 +424,7 @@ module Bundler
Exec.new(options, args).run Exec.new(options, args).run
end end
desc "config NAME [VALUE]", "retrieve or set a configuration value" desc "config NAME [VALUE]", "Retrieve or set a configuration value"
long_desc <<-D long_desc <<-D
Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the
existing value with the newly provided one. existing value with the newly provided one.
@ -386,18 +448,28 @@ module Bundler
Open.new(options, name).run Open.new(options, name).run
end end
if Bundler.feature_flag.console_command?
desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded"
def console(group = nil) def console(group = nil)
# TODO: Remove for 2.0
require "bundler/cli/console" require "bundler/cli/console"
Console.new(options, group).run Console.new(options, group).run
end end
end
desc "version", "Prints the bundler's version information" desc "version", "Prints the bundler's version information"
def version def version
Bundler.ui.info "Bundler version #{Bundler::VERSION}" cli_help = current_command.name == "cli_help"
if cli_help || ARGV.include?("version")
build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})"
end end
map %w(-v --version) => :version
if !cli_help && Bundler.feature_flag.print_only_version_number?
Bundler.ui.info "#{Bundler::VERSION}#{build_info}"
else
Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}"
end
end
map %w[-v --version] => :version
desc "licenses", "Prints the license of all gems in the bundle" desc "licenses", "Prints the license of all gems in the bundle"
def licenses def licenses
@ -413,7 +485,7 @@ module Bundler
end end
end end
desc "viz [OPTIONS]", "Generates a visual dependency graph" desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true
long_desc <<-D long_desc <<-D
Viz generates a PNG file of the current Gemfile as a dependency graph. Viz generates a PNG file of the current Gemfile as a dependency graph.
Viz requires the ruby-graphviz gem (and its dependencies). Viz requires the ruby-graphviz gem (and its dependencies).
@ -431,7 +503,7 @@ module Bundler
old_gem = instance_method(:gem) old_gem = instance_method(:gem)
desc "gem GEM [OPTIONS]", "Creates a skeleton for creating a rubygem" desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem"
method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library." method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library."
method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config gem.coc true`." method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config gem.coc true`."
method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR", method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR",
@ -470,7 +542,7 @@ module Bundler
File.expand_path(File.join(File.dirname(__FILE__), "templates")) File.expand_path(File.join(File.dirname(__FILE__), "templates"))
end end
desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory" desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true
method_option "dry-run", :type => :boolean, :default => false, :banner => method_option "dry-run", :type => :boolean, :default => false, :banner =>
"Only print out changes, do not clean gems" "Only print out changes, do not clean gems"
method_option "force", :type => :boolean, :default => false, :banner => method_option "force", :type => :boolean, :default => false, :banner =>
@ -488,13 +560,13 @@ module Bundler
Platform.new(options).run Platform.new(options).run
end end
desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile" desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true
method_option "source", :type => :string, :banner => method_option "source", :type => :string, :banner =>
"Install gem from the given source" "Install gem from the given source"
method_option "group", :type => :string, :banner => method_option "group", :type => :string, :banner =>
"Install gem into a bundler group" "Install gem into a bundler group"
def inject(name, version) def inject(name, version)
SharedHelpers.major_deprecation "The `inject` command has been replaced by the `add` command" SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command"
require "bundler/cli/inject" require "bundler/cli/inject"
Inject.new(options.dup, name, version).run Inject.new(options.dup, name, version).run
end end
@ -531,7 +603,7 @@ module Bundler
desc "env", "Print information about the environment Bundler is running under" desc "env", "Print information about the environment Bundler is running under"
def env def env
Env.new.write($stdout) Env.write($stdout)
end end
desc "doctor [OPTIONS]", "Checks the bundle for common problems" desc "doctor [OPTIONS]", "Checks the bundle for common problems"
@ -555,15 +627,20 @@ module Bundler
Issue.new.run Issue.new.run
end end
desc "pristine", "Restores installed gems to pristine condition from files located in the gem cache. Gem installed from a git repository will be issued `git checkout --force`." desc "pristine [GEMS...]", "Restores installed gems to pristine condition"
def pristine long_desc <<-D
Restores installed gems to pristine condition from files located in the
gem cache. Gems installed from a git repository will be issued `git
checkout --force`.
D
def pristine(*gems)
require "bundler/cli/pristine" require "bundler/cli/pristine"
Pristine.new.run Pristine.new(gems).run
end end
if Bundler.feature_flag.plugins? if Bundler.feature_flag.plugins?
require "bundler/cli/plugin" require "bundler/cli/plugin"
desc "plugin SUBCOMMAND ...ARGS", "manage the bundler plugins" desc "plugin", "Manage the bundler plugins"
subcommand "plugin", Plugin subcommand "plugin", Plugin
end end
@ -571,14 +648,14 @@ module Bundler
# into the corresponding `bundle help #{command}` call # into the corresponding `bundle help #{command}` call
def self.reformatted_help_args(args) def self.reformatted_help_args(args)
bundler_commands = all_commands.keys bundler_commands = all_commands.keys
help_flags = %w(--help -h) help_flags = %w[--help -h]
exec_commands = %w(e ex exe exec) exec_commands = %w[e ex exe exec]
help_used = args.index {|a| help_flags.include? a } help_used = args.index {|a| help_flags.include? a }
exec_used = args.index {|a| exec_commands.include? a } exec_used = args.index {|a| exec_commands.include? a }
command = args.find {|a| bundler_commands.include? a } command = args.find {|a| bundler_commands.include? a }
if exec_used && help_used if exec_used && help_used
if exec_used + help_used == 1 if exec_used + help_used == 1
%w(help exec) %w[help exec]
else else
args args
end end
@ -613,16 +690,20 @@ module Bundler
end end
end end
def current_command
_, _, config = @_initializer
config[:current_command]
end
def print_command def print_command
return unless Bundler.ui.debug? return unless Bundler.ui.debug?
_, _, config = @_initializer cmd = current_command
current_command = config[:current_command] command_name = cmd.name
command_name = current_command.name
return if PARSEABLE_COMMANDS.include?(command_name) return if PARSEABLE_COMMANDS.include?(command_name)
command = ["bundle", command_name] + args command = ["bundle", command_name] + args
options_to_print = options.dup options_to_print = options.dup
options_to_print.delete_if do |k, v| options_to_print.delete_if do |k, v|
next unless o = current_command.options[k] next unless o = cmd.options[k]
o.default == v o.default == v
end end
command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip
@ -633,8 +714,6 @@ module Bundler
def warn_on_outdated_bundler def warn_on_outdated_bundler
return if Bundler.settings[:disable_version_check] return if Bundler.settings[:disable_version_check]
_, _, config = @_initializer
current_command = config[:current_command]
command_name = current_command.name command_name = current_command.name
return if PARSEABLE_COMMANDS.include?(command_name) return if PARSEABLE_COMMANDS.include?(command_name)
@ -649,8 +728,17 @@ module Bundler
current = Gem::Version.new(VERSION) current = Gem::Version.new(VERSION)
return if current >= latest return if current >= latest
latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max
Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\nTo update, run `gem install bundler#{" --pre" if latest.prerelease?}`" installation = "To install the latest version, run `gem install bundler#{" --pre" if latest.prerelease?}`"
if latest_installed && latest_installed > current
suggestion = "To update to the most recent installed version (#{latest_installed}), run `bundle update --bundler`"
suggestion = "#{installation}\n#{suggestion}" if latest_installed < latest
else
suggestion = installation
end
Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\n#{suggestion}"
rescue rescue
nil nil
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Add class CLI::Add

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Binstubs class CLI::Binstubs
@ -11,8 +10,10 @@ module Bundler
def run def run
Bundler.definition.validate_runtime! Bundler.definition.validate_runtime!
Bundler.settings[:bin] = options["path"] if options["path"] path_option = options["path"]
Bundler.settings[:bin] = nil if options["path"] && options["path"].empty? path_option = nil if path_option && path_option.empty?
Bundler.settings.set_command_option :bin, path_option if options["path"]
Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
installer = Installer.new(Bundler.root, Bundler.definition) installer = Installer.new(Bundler.root, Bundler.definition)
if gems.empty? if gems.empty?
@ -28,10 +29,11 @@ module Bundler
) )
end end
if spec.name == "bundler" if options[:standalone]
Bundler.ui.warn "Sorry, Bundler can only be run via Rubygems." next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler"
elsif options[:standalone] Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do
installer.generate_standalone_bundler_executable_stubs(spec) installer.generate_standalone_bundler_executable_stubs(spec)
end
else else
installer.generate_bundler_executable_stubs(spec, :force => options[:force], :binstubs_cmd => true) installer.generate_bundler_executable_stubs(spec, :force => options[:force], :binstubs_cmd => true)
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Cache class CLI::Cache
attr_reader :options attr_reader :options
@ -10,9 +11,9 @@ module Bundler
Bundler.definition.validate_runtime! Bundler.definition.validate_runtime!
Bundler.definition.resolve_with_cache! Bundler.definition.resolve_with_cache!
setup_cache_all setup_cache_all
Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms") Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"]
Bundler.load.cache Bundler.load.cache
Bundler.settings[:no_prune] = true if options["no-prune"] Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"]
Bundler.load.lock Bundler.load.lock
rescue GemNotFound => e rescue GemNotFound => e
Bundler.ui.error(e.message) Bundler.ui.error(e.message)
@ -23,9 +24,9 @@ module Bundler
private private
def setup_cache_all def setup_cache_all
Bundler.settings[:cache_all] = options[:all] if options.key?("all") Bundler.settings.set_command_option_if_given :cache_all, options[:all]
if Bundler.definition.has_local_dependencies? && !Bundler.settings[:cache_all] if Bundler.definition.has_local_dependencies? && !Bundler.feature_flag.cache_all?
Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \
"to package them as well, please pass the --all flag. This will be the default " \ "to package them as well, please pass the --all flag. This will be the default " \
"on Bundler 2.0." "on Bundler 2.0."

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Check class CLI::Check
attr_reader :options attr_reader :options
@ -8,10 +9,7 @@ module Bundler
end end
def run def run
if options[:path] Bundler.settings.set_command_option_if_given :path, options[:path]
Bundler.settings[:path] = File.expand_path(options[:path])
Bundler.settings[:disable_shared_gems] = true
end
begin begin
definition = Bundler.definition definition = Bundler.definition
@ -28,7 +26,7 @@ module Bundler
not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" }
Bundler.ui.warn "Install missing gems with `bundle install`" Bundler.ui.warn "Install missing gems with `bundle install`"
exit 1 exit 1
elsif !Bundler.default_lockfile.file? && Bundler.settings[:frozen] elsif !Bundler.default_lockfile.file? && Bundler.frozen?
Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present"
exit 1 exit 1
else else

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Clean class CLI::Clean
attr_reader :options attr_reader :options
@ -15,12 +16,10 @@ module Bundler
protected protected
def require_path_or_force def require_path_or_force
if !Bundler.settings[:path] && !options[:force] return unless Bundler.use_system_gems? && !options[:force]
Bundler.ui.error "Cleaning all the gems on your system is dangerous! " \ raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \
"If you're sure you want to remove every system gem not in this " \ "If you're sure you want to remove every system gem not in this " \
"bundle, run `bundle clean --force`." "bundle, run `bundle clean --force`."
exit 1
end
end end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
module CLI::Common module CLI::Common
def self.output_post_install_messages(messages) def self.output_post_install_messages(messages)
@ -14,12 +15,12 @@ module Bundler
end end
def self.output_without_groups_message def self.output_without_groups_message
return unless Bundler.settings.without.any? return if Bundler.settings[:without].empty?
Bundler.ui.confirm without_groups_message Bundler.ui.confirm without_groups_message
end end
def self.without_groups_message def self.without_groups_message
groups = Bundler.settings.without groups = Bundler.settings[:without]
group_list = [groups[0...-1].join(", "), groups[-1..-1]]. group_list = [groups[0...-1].join(", "), groups[-1..-1]].
reject {|s| s.to_s.empty? }.join(" and ") reject {|s| s.to_s.empty? }.join(" and ")
group_str = (groups.size == 1) ? "group" : "groups" group_str = (groups.size == 1) ? "group" : "groups"
@ -89,5 +90,13 @@ module Bundler
def self.patch_level_options(options) def self.patch_level_options(options)
[:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) }
end end
def self.clean_after_install?
clean = Bundler.settings[:clean]
return clean unless clean.nil?
clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil?
clean &&= !Bundler.use_system_gems?
clean
end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Config class CLI::Config
attr_reader :name, :options, :scope, :thor attr_reader :name, :options, :scope, :thor
@ -112,7 +113,7 @@ module Bundler
end end
def valid_scope?(scope) def valid_scope?(scope)
%w(delete local global).include?(scope) %w[delete local global].include?(scope)
end end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Console class CLI::Console
attr_reader :options, :group attr_reader :options, :group
@ -8,7 +9,7 @@ module Bundler
end end
def run def run
Bundler::SharedHelpers.major_deprecation "bundle console will be replaced " \ Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \
"by `bin/console` generated by `bundle gem <name>`" "by `bin/console` generated by `bundle gem <name>`"
group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require

View file

@ -62,6 +62,7 @@ module Bundler
def run def run
Bundler.ui.level = "error" if options[:quiet] Bundler.ui.level = "error" if options[:quiet]
Bundler.settings.validate!
check! check!
definition = Bundler.definition definition = Bundler.definition

View file

@ -1,11 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/current_ruby" require "bundler/current_ruby"
module Bundler module Bundler
class CLI::Exec class CLI::Exec
attr_reader :options, :args, :cmd attr_reader :options, :args, :cmd
RESERVED_SIGNALS = %w(SEGV BUS ILL FPE VTALRM KILL STOP).freeze RESERVED_SIGNALS = %w[SEGV BUS ILL FPE VTALRM KILL STOP].freeze
def initialize(options, args) def initialize(options, args)
@options = options @options = options
@ -72,7 +73,7 @@ module Bundler
signals = Signal.list.keys - RESERVED_SIGNALS signals = Signal.list.keys - RESERVED_SIGNALS
signals.each {|s| trap(s, "DEFAULT") } signals.each {|s| trap(s, "DEFAULT") }
Kernel.load(file) Kernel.load(file)
rescue SystemExit rescue SystemExit, SignalException
raise raise
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
Bundler.ui = ui Bundler.ui = ui

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "pathname" require "pathname"
module Bundler module Bundler
@ -71,10 +72,10 @@ module Bundler
"bin/setup.tt" => "bin/setup" "bin/setup.tt" => "bin/setup"
} }
executables = %w( executables = %w[
bin/console bin/console
bin/setup bin/setup
) ]
templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present? templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present?

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Info class CLI::Info

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Init class CLI::Init
attr_reader :options attr_reader :options
@ -7,8 +8,8 @@ module Bundler
end end
def run def run
if File.exist?("Gemfile") if File.exist?(gemfile)
Bundler.ui.error "Gemfile already exists at #{SharedHelpers.pwd}/Gemfile" Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}"
exit 1 exit 1
end end
@ -21,14 +22,24 @@ module Bundler
spec = Bundler.load_gemspec_uncached(gemspec) spec = Bundler.load_gemspec_uncached(gemspec)
puts "Writing new Gemfile to #{SharedHelpers.pwd}/Gemfile" File.open(gemfile, "wb") do |file|
File.open("Gemfile", "wb") do |file|
file << "# Generated from #{gemspec}\n" file << "# Generated from #{gemspec}\n"
file << spec.to_gemfile file << spec.to_gemfile
end end
else else
puts "Writing new Gemfile to #{SharedHelpers.pwd}/Gemfile" FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile)
FileUtils.cp(File.expand_path("../../templates/Gemfile", __FILE__), "Gemfile") end
puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}"
end
private
def gemfile
@gemfile ||= begin
Bundler.default_gemfile
rescue GemfileNotFound
Bundler.feature_flag.init_gems_rb? ? "gems.rb" : "Gemfile"
end end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Inject class CLI::Inject
attr_reader :options, :name, :version, :group, :source, :gems attr_reader :options, :name, :version, :group, :source, :gems

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Install class CLI::Install
@ -13,17 +12,9 @@ module Bundler
warn_if_root warn_if_root
[:with, :without].each do |option|
if options[option]
options[option] = options[option].join(":").tr(" ", ":").split(":")
end
end
check_for_group_conflicts
normalize_groups normalize_groups
ENV["RB_USER_INSTALL"] = "1" if Bundler::FREEBSD Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD
# Disable color in deployment mode # Disable color in deployment mode
Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment]
@ -32,22 +23,28 @@ module Bundler
check_trust_policy check_trust_policy
if options[:deployment] || options[:frozen] if options[:deployment] || options[:frozen] || Bundler.frozen?
unless Bundler.default_lockfile.exist? unless Bundler.default_lockfile.exist?
flag = options[:deployment] ? "--deployment" : "--frozen" flag = "--deployment flag" if options[:deployment]
raise ProductionError, "The #{flag} flag requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ flag ||= "--frozen flag" if options[:frozen]
flag ||= "deployment setting"
raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \
"sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \
"before deploying." "before deploying."
end end
options[:local] = true if Bundler.app_cache.exist? options[:local] = true if Bundler.app_cache.exist?
Bundler.settings[:frozen] = "1" if Bundler.feature_flag.deployment_means_frozen?
Bundler.settings.set_command_option :deployment, true
else
Bundler.settings.set_command_option :frozen, true
end
end end
# When install is called with --no-deployment, disable deployment mode # When install is called with --no-deployment, disable deployment mode
if options[:deployment] == false if options[:deployment] == false
Bundler.settings.delete(:frozen) Bundler.settings.set_command_option :frozen, nil
options[:system] = true options[:system] = true
end end
@ -56,7 +53,7 @@ module Bundler
Bundler::Fetcher.disable_endpoint = options["full-index"] Bundler::Fetcher.disable_endpoint = options["full-index"]
if options["binstubs"] if options["binstubs"]
Bundler::SharedHelpers.major_deprecation \ Bundler::SharedHelpers.major_deprecation 2,
"The --binstubs option will be removed in favor of `bundle binstubs`" "The --binstubs option will be removed in favor of `bundle binstubs`"
end end
@ -66,24 +63,24 @@ module Bundler
definition.validate_runtime! definition.validate_runtime!
installer = Installer.install(Bundler.root, definition, options) installer = Installer.install(Bundler.root, definition, options)
Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.settings[:frozen] Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen?
Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}."
Bundler::CLI::Common.output_without_groups_message Bundler::CLI::Common.output_without_groups_message
if Bundler.settings[:path] if Bundler.use_system_gems?
absolute_path = File.expand_path(Bundler.settings[:path])
relative_path = absolute_path.sub(File.expand_path(".") + File::SEPARATOR, "." + File::SEPARATOR)
Bundler.ui.confirm "Bundled gems are installed into #{relative_path}."
else
Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed."
else
absolute_path = File.expand_path(Bundler.configured_bundle_path.base_path)
relative_path = absolute_path.sub(File.expand_path(".") + File::SEPARATOR, "." + File::SEPARATOR)
Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`"
end end
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
warn_ambiguous_gems warn_ambiguous_gems
if Bundler.settings[:clean] && Bundler.settings[:path] if CLI::Common.clean_after_install?
require "bundler/cli/clean" require "bundler/cli/clean"
Bundler::CLI::Clean.new(options).run Bundler::CLI::Clean.new(options).run
end end
@ -124,15 +121,11 @@ module Bundler
"#{count} #{count == 1 ? "gem" : "gems"} now installed" "#{count} #{count == 1 ? "gem" : "gems"} now installed"
end end
def check_for_group_conflicts def check_for_group_conflicts_in_cli_options
if options[:without] && options[:with] conflicting_groups = Array(options[:without]) & Array(options[:with])
conflicting_groups = options[:without] & options[:with] return if conflicting_groups.empty?
unless conflicting_groups.empty? raise InvalidOption, "You can't list a group in both with and without." \
Bundler.ui.error "You can't list a group in both, --with and --without." \
" The offending groups are: #{conflicting_groups.join(", ")}." " The offending groups are: #{conflicting_groups.join(", ")}."
exit 1
end
end
end end
def check_for_options_conflicts def check_for_options_conflicts
@ -145,28 +138,29 @@ module Bundler
end end
def check_trust_policy def check_trust_policy
if options["trust-policy"] trust_policy = options["trust-policy"]
unless Bundler.rubygems.security_policies.keys.include?(options["trust-policy"]) unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy)
Bundler.ui.error "Rubygems doesn't know about trust policy '#{options["trust-policy"]}'. " \ raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \
"The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}."
exit 1
end
Bundler.settings["trust-policy"] = options["trust-policy"]
else
Bundler.settings["trust-policy"] = nil if Bundler.settings["trust-policy"]
end end
Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy
end end
def normalize_groups def normalize_groups
Bundler.settings.with = [] if options[:with] && options[:with].empty? options[:with] &&= options[:with].join(":").tr(" ", ":").split(":")
Bundler.settings.without = [] if options[:without] && options[:without].empty? options[:without] &&= options[:without].join(":").tr(" ", ":").split(":")
with = options.fetch("with", []) check_for_group_conflicts_in_cli_options
with |= Bundler.settings.with.map(&:to_s)
Bundler.settings.set_command_option :with, nil if options[:with] == []
Bundler.settings.set_command_option :without, nil if options[:without] == []
with = options.fetch(:with, [])
with |= Bundler.settings[:with].map(&:to_s)
with -= options[:without] if options[:without] with -= options[:without] if options[:without]
without = options.fetch("without", []) without = options.fetch(:without, [])
without |= Bundler.settings.without.map(&:to_s) without |= Bundler.settings[:without].map(&:to_s)
without -= options[:with] if options[:with] without -= options[:with] if options[:with]
options[:with] = with options[:with] = with
@ -174,28 +168,34 @@ module Bundler
end end
def normalize_settings def normalize_settings
Bundler.settings[:path] = nil if options[:system] Bundler.settings.set_command_option :path, nil if options[:system]
Bundler.settings[:path] = "vendor/bundle" if options[:deployment] Bundler.settings.set_command_option :path, "vendor/bundle" if options[:deployment]
Bundler.settings[:path] = options["path"] if options["path"] Bundler.settings.set_command_option_if_given :path, options["path"]
Bundler.settings[:path] ||= "bundle" if options["standalone"] Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil?
Bundler.settings[:bin] = options["binstubs"] if options["binstubs"] bin_option = options["binstubs"]
Bundler.settings[:bin] = nil if options["binstubs"] && options["binstubs"].empty? bin_option = nil if bin_option && bin_option.empty?
Bundler.settings.set_command_option :bin, bin_option if options["binstubs"]
Bundler.settings[:shebang] = options["shebang"] if options["shebang"] Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
Bundler.settings[:jobs] = options["jobs"] if options["jobs"] Bundler.settings.set_command_option_if_given :jobs, options["jobs"]
Bundler.settings[:no_prune] = true if options["no-prune"] Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"]
Bundler.settings[:no_install] = true if options["no-install"] Bundler.settings.set_command_option_if_given :no_install, options["no-install"]
Bundler.settings[:clean] = options["clean"] if options["clean"] Bundler.settings.set_command_option_if_given :clean, options["clean"]
Bundler.settings.without = options[:without] unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with]
Bundler.settings.with = options[:with] # need to nil them out first to get around validation for backwards compatibility
Bundler.settings.set_command_option :without, nil
Bundler.settings.set_command_option :with, nil
Bundler.settings.set_command_option :without, options[:without] - options[:with]
Bundler.settings.set_command_option :with, options[:with]
end
Bundler.settings[:disable_shared_gems] = Bundler.settings[:path] ? true : nil options[:force] = options[:redownload]
end end
def warn_ambiguous_gems def warn_ambiguous_gems

View file

@ -26,7 +26,7 @@ module Bundler
EOS EOS
Bundler.ui.info Bundler::Env.new.report Bundler.ui.info Bundler::Env.report
Bundler.ui.info "\n## Bundle Doctor" Bundler.ui.info "\n## Bundle Doctor"
doctor doctor

22
lib/bundler/cli/list.rb Normal file
View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Bundler
class CLI::List
def initialize(options)
@options = options
end
def run
specs = Bundler.load.specs.reject {|s| s.name == "bundler" }.sort_by(&:name)
return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"]
return Bundler.ui.info "No gems in the Gemfile" if specs.empty?
Bundler.ui.info "Gems included by the bundle:"
specs.each do |s|
Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})"
end
Bundler.ui.info "Use `bundle info` to print more detailed information about a gem"
end
end
end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Lock class CLI::Lock

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
require "shellwords" require "shellwords"
module Bundler module Bundler
@ -17,7 +17,7 @@ module Bundler
path = spec.full_gem_path path = spec.full_gem_path
Dir.chdir(path) do Dir.chdir(path) do
command = Shellwords.split(editor) + [path] command = Shellwords.split(editor) + [path]
Bundler.with_clean_env do Bundler.with_original_env do
system(*command) system(*command)
end || Bundler.ui.info("Could not run '#{command.join(" ")}'") end || Bundler.ui.info("Could not run '#{command.join(" ")}'")
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Outdated class CLI::Outdated
@ -46,7 +45,7 @@ module Bundler
Bundler::CLI::Common.patch_level_options(options).any? Bundler::CLI::Common.patch_level_options(options).any?
filter_options_patch = options.keys & filter_options_patch = options.keys &
%w(filter-major filter-minor filter-patch) %w[filter-major filter-minor filter-patch]
definition_resolution = proc do definition_resolution = proc do
options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely!
@ -214,13 +213,19 @@ module Bundler
end end
def check_for_deployment_mode def check_for_deployment_mode
if Bundler.settings[:frozen] return unless Bundler.frozen?
suggested_command = if Bundler.settings.locations("frozen")[:global]
"bundle config --delete frozen"
elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
"bundle config --delete deployment"
else
"bundle install --no-deployment"
end
raise ProductionError, "You are trying to check outdated gems in " \ raise ProductionError, "You are trying to check outdated gems in " \
"deployment mode. Run `bundle outdated` elsewhere.\n" \ "deployment mode. Run `bundle outdated` elsewhere.\n" \
"\nIf this is a development machine, remove the " \ "\nIf this is a development machine, remove the " \
"#{Bundler.default_gemfile} freeze" \ "#{Bundler.default_gemfile} freeze" \
"\nby running `bundle install --no-deployment`." "\nby running `#{suggested_command}`."
end
end end
def update_present_via_semver_portions(current_spec, active_spec, options) def update_present_via_semver_portions(current_spec, active_spec, options)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Package class CLI::Package
attr_reader :options attr_reader :options
@ -9,15 +10,15 @@ module Bundler
def run def run
Bundler.ui.level = "error" if options[:quiet] Bundler.ui.level = "error" if options[:quiet]
Bundler.settings[:path] = File.expand_path(options[:path]) if options[:path] Bundler.settings.set_command_option_if_given :path, options[:path]
Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms") Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"]
Bundler.settings[:cache_path] = options["cache-path"] if options.key?("cache-path") Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"]
setup_cache_all setup_cache_all
install install
# TODO: move cache contents here now that all bundles are locked # TODO: move cache contents here now that all bundles are locked
custom_path = Pathname.new(options[:path]) if options[:path] custom_path = Bundler.settings[:path] if options[:path]
Bundler.load.cache(custom_path) Bundler.load.cache(custom_path)
end end
@ -34,9 +35,11 @@ module Bundler
end end
def setup_cache_all def setup_cache_all
Bundler.settings[:cache_all] = options[:all] if options.key?("all") all = options.fetch(:all, Bundler.feature_flag.cache_command_is_package? || nil)
if Bundler.definition.has_local_dependencies? && !Bundler.settings[:cache_all] Bundler.settings.set_command_option_if_given :cache_all, all
if Bundler.definition.has_local_dependencies? && !Bundler.feature_flag.cache_all?
Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \
"to package them as well, please pass the --all flag. This will be the default " \ "to package them as well, please pass the --all flag. This will be the default " \
"on Bundler 2.0." "on Bundler 2.0."

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Platform class CLI::Platform
attr_reader :options attr_reader :options

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/vendored_thor" require "bundler/vendored_thor"
module Bundler module Bundler
class CLI::Plugin < Thor class CLI::Plugin < Thor

View file

@ -1,15 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Pristine class CLI::Pristine
def initialize(gems)
@gems = gems
end
def run def run
CLI::Common.ensure_all_gems_in_lockfile!(@gems)
definition = Bundler.definition definition = Bundler.definition
definition.validate_runtime! definition.validate_runtime!
installer = Bundler::Installer.new(Bundler.root, definition) installer = Bundler::Installer.new(Bundler.root, definition)
Bundler.load.specs.each do |spec| Bundler.load.specs.each do |spec|
next if spec.name == "bundler" # Source::Rubygems doesn't install bundler next if spec.name == "bundler" # Source::Rubygems doesn't install bundler
next if !@gems.empty? && !@gems.include?(spec.name)
gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})"
gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY
@ -21,13 +26,15 @@ module Bundler
Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.")
next next
end end
FileUtils.rm_rf spec.full_gem_path
when Source::Git when Source::Git
source.remote! source.remote!
FileUtils.rm_rf spec.full_gem_path
else else
Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
next next
end end
FileUtils.rm_rf spec.full_gem_path
Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Show class CLI::Show

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/cli/common"
module Bundler module Bundler
class CLI::Update class CLI::Update
@ -17,7 +16,18 @@ module Bundler
sources = Array(options[:source]) sources = Array(options[:source])
groups = Array(options[:group]).map(&:to_sym) groups = Array(options[:group]).map(&:to_sym)
if gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler] full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler]
if full_update && !options[:all]
if Bundler.feature_flag.update_requires_all_flag?
raise InvalidOption, "To update everything, pass the `--all` flag."
end
SharedHelpers.major_deprecation 2, "Pass --all to `bundle update` to update everything"
elsif !full_update && options[:all]
raise InvalidOption, "Cannot specify --all along with specific options."
end
if full_update
# We're doing a full update # We're doing a full update
Bundler.definition(true) Bundler.definition(true)
else else
@ -33,7 +43,8 @@ module Bundler
end end
Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby],
:lock_shared_dependencies => options[:conservative]) :lock_shared_dependencies => options[:conservative],
:bundler => options[:bundler])
end end
Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
@ -44,17 +55,32 @@ module Bundler
opts["update"] = true opts["update"] = true
opts["local"] = options[:local] opts["local"] = options[:local]
Bundler.settings[:jobs] = opts["jobs"] if opts["jobs"] Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
Bundler.definition.validate_runtime! Bundler.definition.validate_runtime!
installer = Installer.install Bundler.root, Bundler.definition, opts installer = Installer.install Bundler.root, Bundler.definition, opts
Bundler.load.cache if Bundler.app_cache.exist? Bundler.load.cache if Bundler.app_cache.exist?
if Bundler.settings[:clean] && Bundler.settings[:path] if CLI::Common.clean_after_install?
require "bundler/cli/clean" require "bundler/cli/clean"
Bundler::CLI::Clean.new(options).run Bundler::CLI::Clean.new(options).run
end end
if locked_gems = Bundler.definition.locked_gems
gems.each do |name|
locked_version = locked_gems.specs.find {|s| s.name == name }.version
new_version = Bundler.definition.specs[name].first
new_version &&= new_version.version
if !new_version
Bundler.ui.warn "Bundler attempted to update #{name} but it was removed from the bundle"
elsif new_version < locked_version
Bundler.ui.warn "Bundler attempted to update #{name} but its version regressed from #{locked_version} to #{new_version}"
elsif new_version == locked_version
Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same"
end
end
end
Bundler.ui.confirm "Bundle updated!" Bundler.ui.confirm "Bundle updated!"
Bundler::CLI::Common.output_without_groups_message Bundler::CLI::Common.output_without_groups_message
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages Bundler::CLI::Common.output_post_install_messages installer.post_install_messages

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class CLI::Viz class CLI::Viz
attr_reader :options, :gem_name attr_reader :options, :gem_name

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "pathname" require "pathname"
require "set" require "set"

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "digest/md5"
module Bundler module Bundler
class CompactIndexClient class CompactIndexClient
@ -68,7 +67,7 @@ module Bundler
def info_path(name) def info_path(name)
name = name.to_s name = name.to_s
if name =~ /[^a-z0-9_-]/ if name =~ /[^a-z0-9_-]/
name += "-#{Digest::MD5.hexdigest(name).downcase}" name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
info_roots.last.join(name) info_roots.last.join(name)
else else
info_roots.first.join(name) info_roots.first.join(name)

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "fileutils"
require "bundler/vendored_fileutils"
require "stringio" require "stringio"
require "tmpdir"
require "zlib" require "zlib"
module Bundler module Bundler
@ -22,6 +22,7 @@ module Bundler
def initialize(fetcher) def initialize(fetcher)
@fetcher = fetcher @fetcher = fetcher
require "tmpdir"
end end
def update(local_path, remote_path, retrying = nil) def update(local_path, remote_path, retrying = nil)
@ -98,7 +99,7 @@ module Bundler
# because we need to preserve \n line endings on windows when calculating # because we need to preserve \n line endings on windows when calculating
# the checksum # the checksum
SharedHelpers.filesystem_access(path, :read) do SharedHelpers.filesystem_access(path, :read) do
Digest::MD5.hexdigest(IO.read(path)) SharedHelpers.digest(:MD5).hexdigest(IO.read(path))
end end
end end
end end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: false
require "rubygems"
require "bundler/version"
if Bundler::VERSION.split(".").first.to_i >= 2
if Gem::Version.new(Object::RUBY_VERSION.dup) < Gem::Version.new("2.3")
abort "Bundler 2 requires Ruby 2.3 or later. Either install bundler 1 or update to a supported Ruby version."
end
if Gem::Version.new(Gem::VERSION.dup) < Gem::Version.new("2.5")
abort "Bundler 2 requires RubyGems 2.5 or later. Either install bundler 1 or update to a supported RubyGems version."
end
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
# Returns current version of Ruby # Returns current version of Ruby
# #
@ -8,7 +9,7 @@ module Bundler
end end
class CurrentRuby class CurrentRuby
KNOWN_MINOR_VERSIONS = %w( KNOWN_MINOR_VERSIONS = %w[
1.8 1.8
1.9 1.9
2.0 2.0
@ -17,11 +18,11 @@ module Bundler
2.3 2.3
2.4 2.4
2.5 2.5
).freeze ].freeze
KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
KNOWN_PLATFORMS = %w( KNOWN_PLATFORMS = %w[
jruby jruby
maglev maglev
mingw mingw
@ -31,7 +32,7 @@ module Bundler
rbx rbx
ruby ruby
x64_mingw x64_mingw
).freeze ].freeze
def ruby? def ruby?
!mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev") !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev")

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/lockfile_parser" require "bundler/lockfile_parser"
require "digest/sha1"
require "set" require "set"
module Bundler module Bundler
@ -14,7 +14,9 @@ module Bundler
:locked_gems, :locked_gems,
:platforms, :platforms,
:requires, :requires,
:ruby_version :ruby_version,
:lockfile,
:gemfiles
) )
# Given a gemfile and lockfile creates a Bundler definition # Given a gemfile and lockfile creates a Bundler definition
@ -51,8 +53,16 @@ module Bundler
# to be updated or true if all gems should be updated # to be updated or true if all gems should be updated
# @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
# @param optional_groups [Array(String)] A list of optional groups # @param optional_groups [Array(String)] A list of optional groups
def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = []) def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
@unlocking = unlock == true || !unlock.empty? if [true, false].include?(unlock)
@unlocking_bundler = false
@unlocking = unlock
else
unlock = unlock.dup
@unlocking_bundler = unlock.delete(:bundler)
unlock.delete_if {|_k, v| Array(v).empty? }
@unlocking = !unlock.empty?
end
@dependencies = dependencies @dependencies = dependencies
@sources = sources @sources = sources
@ -61,6 +71,7 @@ module Bundler
@remote = false @remote = false
@specs = nil @specs = nil
@ruby_version = ruby_version @ruby_version = ruby_version
@gemfiles = gemfiles
@lockfile = lockfile @lockfile = lockfile
@lockfile_contents = String.new @lockfile_contents = String.new
@ -102,7 +113,7 @@ module Bundler
end end
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
add_current_platform unless Bundler.settings[:frozen] add_current_platform unless Bundler.frozen?
converge_path_sources_to_gemspec_sources converge_path_sources_to_gemspec_sources
@path_changes = converge_paths @path_changes = converge_paths
@ -167,9 +178,8 @@ module Bundler
"to a different version of #{locked_gem} that hasn't been removed in order to install." "to a different version of #{locked_gem} that hasn't been removed in order to install."
end end
unless specs["bundler"].any? unless specs["bundler"].any?
local = Bundler.settings[:frozen] ? rubygems_index : index bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
bundler = local.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler
specs["bundler"] = bundler if bundler
end end
specs specs
@ -194,10 +204,19 @@ module Bundler
missing missing
end end
def missing_dependencies def missing_specs?
missing = [] missing = missing_specs
resolve.materialize(current_dependencies, missing) return false if missing.empty?
missing Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}"
true
rescue BundlerError => e
@index = nil
@resolve = nil
@specs = nil
@gem_version_promoter = create_gem_version_promoter
Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
true
end end
def requested_specs def requested_specs
@ -226,7 +245,10 @@ module Bundler
def resolve def resolve
@resolve ||= begin @resolve ||= begin
last_resolve = converge_locked_specs last_resolve = converge_locked_specs
if Bundler.settings[:frozen] || (!unlocking? && nothing_changed?) if Bundler.frozen?
Bundler.ui.debug "Frozen, using resolution from the lockfile"
last_resolve
elsif !unlocking? && nothing_changed?
Bundler.ui.debug("Found no changes, using resolution from the lockfile") Bundler.ui.debug("Found no changes, using resolution from the lockfile")
last_resolve last_resolve
else else
@ -242,25 +264,44 @@ module Bundler
dependency_names = @dependencies.map(&:name) dependency_names = @dependencies.map(&:name)
sources.all_sources.each do |source| sources.all_sources.each do |source|
source.dependency_names = dependency_names.dup source.dependency_names = dependency_names - pinned_spec_names(source)
idx.add_source source.specs idx.add_source source.specs
dependency_names -= pinned_spec_names(source.specs)
dependency_names.concat(source.unmet_deps).uniq! dependency_names.concat(source.unmet_deps).uniq!
end end
idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel)
idx << Gem::Specification.new("rubygems\0", Gem::VERSION) double_check_for_index(idx, dependency_names)
end end
end end
# used when frozen is enabled so we can find the bundler # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both
# spec, even if (say) a git gem is not checked out. # sources A and B. At this point, the API request will have found all the versions of Bar in source A,
def rubygems_index # but will not have found any versions of Bar from source B, which is a problem if the requested version
@rubygems_index ||= Index.build do |idx| # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for
sources.rubygems_sources.each do |rubygems| # each spec we found, we add all possible versions from all sources to the index.
idx.add_source rubygems.specs def double_check_for_index(idx, dependency_names)
end 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, :override_dupes)
end
break if idxcount == idx.size
end end
end end
private :double_check_for_index
def has_rubygems_remotes? def has_rubygems_remotes?
sources.rubygems_sources.any? {|s| s.remotes.any? } sources.rubygems_sources.any? {|s| s.remotes.any? }
@ -295,10 +336,10 @@ module Bundler
end end
end end
preserve_unknown_sections ||= !updating_major && (Bundler.settings[:frozen] || !unlocking?) preserve_unknown_sections ||= !updating_major && (Bundler.frozen? || !(unlocking? || @unlocking_bundler))
return if lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) return if lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
if Bundler.settings[:frozen] if Bundler.frozen?
Bundler.ui.error "Cannot write a changed lockfile while frozen." Bundler.ui.error "Cannot write a changed lockfile while frozen."
return return
end end
@ -338,51 +379,8 @@ module Bundler
end end
def to_lock def to_lock
out = String.new require "bundler/lockfile_generator"
LockfileGenerator.generate(self)
sources.lock_sources.each do |source|
# Add the source header
out << source.to_lock
# Find all specs for this source
resolve.
select {|s| source.can_lock?(s) }.
# This needs to be sorted by full name so that
# gems with the same name, but different platform
# are ordered consistently
sort_by(&:full_name).
each do |spec|
next if spec.name == "bundler"
out << spec.to_lock
end
out << "\n"
end
out << "PLATFORMS\n"
platforms.map(&:to_s).sort.each do |p|
out << " #{p}\n"
end
out << "\n"
out << "DEPENDENCIES\n"
handled = []
dependencies.sort_by(&:to_s).each do |dep|
next if handled.include?(dep.name)
out << dep.to_lock
handled << dep.name
end
if locked_ruby_version
out << "\nRUBY VERSION\n"
out << " #{locked_ruby_version}\n"
end
# Record the version of Bundler that was used to create the lockfile
out << "\nBUNDLED WITH\n"
out << " #{locked_bundler_version}\n"
out
end end
def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
@ -392,8 +390,13 @@ module Bundler
"updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control."
unless explicit_flag unless explicit_flag
suggested_command = if Bundler.settings.locations("frozen")[:global]
suggested_command = Bundler.settings.locations("frozen")[:global] == "1" ? "bundle config --delete frozen" : "bundle install --no-deployment" "bundle config --delete frozen"
elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
"bundle config --delete deployment"
else
"bundle install --no-deployment"
end
msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
"freeze \nby running `#{suggested_command}`." "freeze \nby running `#{suggested_command}`."
end end
@ -417,8 +420,8 @@ module Bundler
# Check if it is possible that the source is only changed thing # Check if it is possible that the source is only changed thing
if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?) if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
new_sources.reject! {|source| source.is_a_path? && source.path.exist? } new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
deleted_sources.reject! {|source| source.is_a_path? && source.path.exist? } deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
end end
if @locked_sources != gemfile_sources if @locked_sources != gemfile_sources
@ -511,7 +514,7 @@ module Bundler
def add_current_platform def add_current_platform
current_platform = Bundler.local_platform current_platform = Bundler.local_platform
add_platform(current_platform) if Bundler.settings[:specific_platform] add_platform(current_platform) if Bundler.feature_flag.specific_platform?
add_platform(generic(current_platform)) add_platform(generic(current_platform))
end end
@ -558,10 +561,7 @@ module Bundler
end end
def pretty_dep(dep, source = false) def pretty_dep(dep, source = false)
msg = String.new(dep.name) SharedHelpers.pretty_dependency(dep, source)
msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
msg << " from the `#{dep.source}` source" if source && dep.source
msg
end end
# Check if the specs of the given source changed # Check if the specs of the given source changed
@ -585,6 +585,9 @@ module Bundler
# order here matters, since Index#== is checking source.specs.include?(locked_index) # order here matters, since Index#== is checking source.specs.include?(locked_index)
locked_index != source.specs locked_index != source.specs
rescue PathError, GitError => e
Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})"
false
end end
# Get all locals and override their matching sources. # Get all locals and override their matching sources.
@ -632,22 +635,32 @@ module Bundler
end end
end end
def converge_sources def converge_rubygems_sources
return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
changes = false changes = false
# Get the Rubygems sources from the Gemfile.lock # Get the RubyGems sources from the Gemfile.lock
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
# Get the Rubygems remotes from the Gemfile # Get the RubyGems remotes from the Gemfile
actual_remotes = sources.rubygems_remotes actual_remotes = sources.rubygems_remotes
# If there is a Rubygems source in both # If there is a RubyGems source in both
if !locked_gem_sources.empty? && !actual_remotes.empty? if !locked_gem_sources.empty? && !actual_remotes.empty?
locked_gem_sources.each do |locked_gem| locked_gem_sources.each do |locked_gem|
# Merge the remotes from the Gemfile into the Gemfile.lock # Merge the remotes from the Gemfile into the Gemfile.lock
changes |= locked_gem.replace_remotes(actual_remotes) changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
end end
end end
changes
end
def converge_sources
changes = false
changes |= converge_rubygems_sources
# Replace the sources from the Gemfile with the sources from the Gemfile.lock, # Replace the sources from the Gemfile with the sources from the Gemfile.lock,
# if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
# source in the Gemfile.lock, use the one from the Gemfile. # source in the Gemfile.lock, use the one from the Gemfile.
@ -669,7 +682,7 @@ module Bundler
end end
def converge_dependencies def converge_dependencies
frozen = Bundler.settings[:frozen] frozen = Bundler.frozen?
(@dependencies + @locked_deps.values).each do |dep| (@dependencies + @locked_deps.values).each do |dep|
locked_source = @locked_deps[dep.name] locked_source = @locked_deps[dep.name]
# This is to make sure that if bundler is installing in deployment mode and # This is to make sure that if bundler is installing in deployment mode and
@ -739,6 +752,8 @@ module Bundler
end end
end end
unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec?
converged = [] converged = []
@locked_specs.each do |s| @locked_specs.each do |s|
# Replace the locked dependency's source with the equivalent source from the Gemfile # Replace the locked dependency's source with the equivalent source from the Gemfile
@ -746,21 +761,33 @@ module Bundler
s.source = (dep && dep.source) || sources.get(s.source) s.source = (dep && dep.source) || sources.get(s.source)
# Don't add a spec to the list if its source is expired. For example, # Don't add a spec to the list if its source is expired. For example,
# if you change a Git gem to Rubygems. # if you change a Git gem to RubyGems.
next if s.source.nil? next if s.source.nil?
next if @unlock[:sources].include?(s.source.name) next if @unlock[:sources].include?(s.source.name)
# XXX This is a backwards-compatibility fix to preserve the ability to # 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 # unlock a single gem by passing its name via `--source`. See issue #3759
# TODO: delete in Bundler 2 # TODO: delete in Bundler 2
next if @unlock[:sources].include?(s.name) 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 # If the spec is from a path source and it doesn't exist anymore
# then we unlock it. # then we unlock it.
# Path sources have special logic # Path sources have special logic
if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
other = s.source.specs[s].first other_sources_specs = begin
s.source.specs
rescue PathError, GitError
# if we won't need the source (according to the lockfile),
# don't error if the path/git source isn't available
next if @locked_specs.
for(requested_dependencies, [], false, true, false).
none? {|locked_spec| locked_spec.source == s.source }
raise
end
other = other_sources_specs[s].first
# If the spec is no longer in the path source, unlock it. This # If the spec is no longer in the path source, unlock it. This
# commonly happens if the version changed in the gemspec # commonly happens if the version changed in the gemspec
@ -807,17 +834,21 @@ module Bundler
# the metadata dependencies here # the metadata dependencies here
def expanded_dependencies def expanded_dependencies
@expanded_dependencies ||= begin @expanded_dependencies ||= begin
expand_dependencies(dependencies + metadata_dependencies, @remote)
end
end
def metadata_dependencies
@metadata_dependencies ||= begin
ruby_versions = concat_ruby_version_requirements(@ruby_version) ruby_versions = concat_ruby_version_requirements(@ruby_version)
if ruby_versions.empty? || !@ruby_version.exact? if ruby_versions.empty? || !@ruby_version.exact?
concat_ruby_version_requirements(RubyVersion.system) concat_ruby_version_requirements(RubyVersion.system)
concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby] concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
end end
[
metadata_dependencies = [
Dependency.new("ruby\0", ruby_versions), Dependency.new("ruby\0", ruby_versions),
Dependency.new("rubygems\0", Gem::VERSION), Dependency.new("rubygems\0", Gem::VERSION),
] ]
expand_dependencies(dependencies + metadata_dependencies, @remote)
end end
end end
@ -838,11 +869,12 @@ module Bundler
end end
def expand_dependencies(dependencies, remote = false) def expand_dependencies(dependencies, remote = false)
sorted_platforms = Resolver.sort_platforms(@platforms)
deps = [] deps = []
dependencies.each do |dep| dependencies.each do |dep|
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
next if !remote && !dep.current_platform? next if !remote && !dep.current_platform?
platforms = dep.gem_platforms(@platforms) platforms = dep.gem_platforms(sorted_platforms)
if platforms.empty? if platforms.empty?
mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] } mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] }
Bundler.ui.warn \ Bundler.ui.warn \
@ -872,30 +904,33 @@ module Bundler
# Record the specs available in each gem's source, so that those # Record the specs available in each gem's source, so that those
# specs will be available later when the resolver knows where to # specs will be available later when the resolver knows where to
# look for that gemspec (or its dependencies) # look for that gemspec (or its dependencies)
source_requirements = {} default = sources.default_source
source_requirements = { :default => default }
default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
dependencies.each do |dep| dependencies.each do |dep|
next unless dep.source next unless source = dep.source || default
source_requirements[dep.name] = dep.source.specs source_requirements[dep.name] = source
end end
metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source
end
source_requirements["bundler"] = sources.metadata_source # needs to come last to override
source_requirements source_requirements
end end
def pinned_spec_names(specs) def pinned_spec_names(skip = nil)
names = [] pinned_names = []
specs.each do |s| default = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && sources.default_source
# TODO: when two sources without blocks is an error, we can change @dependencies.each do |dep|
# this check to !s.source.is_a?(Source::LocalRubygems). For now, next unless dep_source = dep.source || default
# we need to ask every Rubygems for every gem name. next if dep_source == skip
if s.source.is_a?(Source::Git) || s.source.is_a?(Source::Path) pinned_names << dep.name
names << s.name
end end
end pinned_names
names.uniq!
names
end end
def requested_groups def requested_groups
groups - Bundler.settings.without - @optional_groups + Bundler.settings.with groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
end end
def lockfiles_equal?(current, proposed, preserve_unknown_sections) def lockfiles_equal?(current, proposed, preserve_unknown_sections)
@ -930,11 +965,20 @@ module Bundler
def additional_base_requirements_for_resolve def additional_base_requirements_for_resolve
return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions? return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
dependencies_by_name = dependencies.group_by(&:name)
@locked_gems.specs.reduce({}) do |requirements, locked_spec| @locked_gems.specs.reduce({}) do |requirements, locked_spec|
dep = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}") name = locked_spec.name
requirements[locked_spec.name] = DepProxy.new(dep, locked_spec.platform) next requirements if @locked_deps[name] != dependencies_by_name[name]
dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
requirements[name] = DepProxy.new(dep, locked_spec.platform)
requirements requirements
end.values end.values
end end
def equivalent_rubygems_remotes?(source)
return false unless source.is_a?(Source::Rubygems)
Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class DepProxy class DepProxy
attr_reader :__platform, :dep attr_reader :__platform, :dep
@ -13,6 +14,7 @@ module Bundler
end end
def ==(other) def ==(other)
return if other.nil?
dep == other.dep && __platform == other.__platform dep == other.dep && __platform == other.__platform
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "rubygems/dependency" require "rubygems/dependency"
require "bundler/shared_helpers" require "bundler/shared_helpers"
require "bundler/rubygems_ext" require "bundler/rubygems_ext"
@ -90,16 +91,14 @@ module Bundler
@autorequire = Array(options["require"] || []) if options.key?("require") @autorequire = Array(options["require"] || []) if options.key?("require")
end end
# Returns the platforms this dependency is valid for, in the same order as
# passed in the `valid_platforms` parameter
def gem_platforms(valid_platforms) def gem_platforms(valid_platforms)
return valid_platforms if @platforms.empty? return valid_platforms if @platforms.empty?
platforms = [] @gem_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.uniq
@platforms.each do |p|
platform = PLATFORM_MAP[p] valid_platforms & @gem_platforms
next unless valid_platforms.include?(platform)
platforms |= [platform]
end
platforms
end end
def should_include? def should_include?

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/shared_helpers" require "bundler/shared_helpers"
Bundler::SharedHelpers.major_deprecation "Bundler no longer integrates with " \ Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \
"Capistrano, but Capistrano provides its own integration with " \ "Capistrano, but Capistrano provides its own integration with " \
"Bundler via the capistrano-bundler gem. Use it instead." "Bundler via the capistrano-bundler gem. Use it instead."

View file

@ -1,11 +1,22 @@
# frozen_string_literal: true # frozen_string_literal: true
begin
require "rubygems/deprecate"
rescue LoadError
# it's fine if it doesn't exist on the current RubyGems...
nil
end
module Bundler module Bundler
if defined? ::Deprecate if defined? Bundler::Deprecate
# nothing to do!
elsif defined? ::Deprecate
Deprecate = ::Deprecate Deprecate = ::Deprecate
elsif defined? Gem::Deprecate elsif defined? Gem::Deprecate
Deprecate = Gem::Deprecate Deprecate = Gem::Deprecate
else else
class Deprecate; end class Deprecate
end
end end
unless Deprecate.respond_to?(:skip_during) unless Deprecate.respond_to?(:skip_during)
@ -20,7 +31,7 @@ module Bundler
unless Deprecate.respond_to?(:skip) unless Deprecate.respond_to?(:skip)
def Deprecate.skip def Deprecate.skip
@skip @skip ||= false
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/dependency" require "bundler/dependency"
require "bundler/ruby_dsl" require "bundler/ruby_dsl"
@ -14,6 +15,9 @@ module Bundler
VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze
VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules
platform platforms type source install_if].freeze
attr_reader :gemspecs attr_reader :gemspecs
attr_accessor :dependencies attr_accessor :dependencies
@ -30,14 +34,16 @@ module Bundler
@ruby_version = nil @ruby_version = nil
@gemspecs = [] @gemspecs = []
@gemfile = nil @gemfile = nil
@gemfiles = []
add_git_sources add_git_sources
end end
def eval_gemfile(gemfile, contents = nil) def eval_gemfile(gemfile, contents = nil)
expanded_gemfile_path = Pathname.new(gemfile).expand_path expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent)
original_gemfile = @gemfile original_gemfile = @gemfile
@gemfile = expanded_gemfile_path @gemfile = expanded_gemfile_path
contents ||= Bundler.read_file(gemfile.to_s) @gemfiles << expanded_gemfile_path
contents ||= Bundler.read_file(@gemfile.to_s)
instance_eval(contents.dup.untaint, gemfile.to_s, 1) instance_eval(contents.dup.untaint, gemfile.to_s, 1)
rescue Exception => e rescue Exception => e
message = "There was an error " \ message = "There was an error " \
@ -95,10 +101,10 @@ module Bundler
# if there's already a dependency with this name we try to prefer one # if there's already a dependency with this name we try to prefer one
if current = @dependencies.find {|d| d.name == dep.name } if current = @dependencies.find {|d| d.name == dep.name }
deleted_dep = @dependencies.delete(current) if current.type == :development
if current.requirement != dep.requirement if current.requirement != dep.requirement
if current.type == :development unless deleted_dep
@dependencies.delete current
else
return if dep.type == :development return if dep.type == :development
raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
"You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})"
@ -111,9 +117,7 @@ module Bundler
end end
if current.source != dep.source if current.source != dep.source
if current.type == :development unless deleted_dep
@dependencies.delete current
else
return if dep.type == :development return if dep.type == :development
raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
"You specified that #{dep.name} (#{dep.requirement}) should come from " \ "You specified that #{dep.name} (#{dep.requirement}) should come from " \
@ -128,10 +132,12 @@ module Bundler
def source(source, *args, &blk) def source(source, *args, &blk)
options = args.last.is_a?(Hash) ? args.pop.dup : {} options = args.last.is_a?(Hash) ? args.pop.dup : {}
options = normalize_hash(options) options = normalize_hash(options)
source = normalize_source(source)
if options.key?("type") if options.key?("type")
options["type"] = options["type"].to_s options["type"] = options["type"].to_s
unless Plugin.source?(options["type"]) unless Plugin.source?(options["type"])
raise "No sources available for #{options["type"]}" raise InvalidOption, "No plugin sources available for #{options["type"]}"
end end
unless block_given? unless block_given?
@ -141,12 +147,10 @@ module Bundler
source_opts = options.merge("uri" => source) source_opts = options.merge("uri" => source)
with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) with_source(@sources.add_plugin_source(options["type"], source_opts), &blk)
elsif block_given? elsif block_given?
source = normalize_source(source)
with_source(@sources.add_rubygems_source("remotes" => source), &blk) with_source(@sources.add_rubygems_source("remotes" => source), &blk)
else else
source = normalize_source(source)
check_primary_source_safety(@sources) check_primary_source_safety(@sources)
@sources.add_rubygems_remote(source) @sources.global_rubygems_source = source
end end
end end
@ -164,6 +168,19 @@ module Bundler
end end
def path(path, options = {}, &blk) 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( source_options = normalize_hash(options).merge(
"path" => Pathname.new(path), "path" => Pathname.new(path),
"root_path" => gemfile_root, "root_path" => gemfile_root,
@ -190,6 +207,7 @@ module Bundler
def github(repo, options = {}) def github(repo, options = {})
raise ArgumentError, "GitHub sources require a block" unless block_given? raise ArgumentError, "GitHub sources require a block" unless block_given?
raise DeprecatedError, "The #github method has been removed" if Bundler.feature_flag.skip_default_git_sources?
github_uri = @git_sources["github"].call(repo) github_uri = @git_sources["github"].call(repo)
git_options = normalize_hash(options).merge("uri" => github_uri) git_options = normalize_hash(options).merge("uri" => github_uri)
git_source = @sources.add_git_source(git_options) git_source = @sources.add_git_source(git_options)
@ -197,16 +215,16 @@ module Bundler
end end
def to_definition(lockfile, unlock) def to_definition(lockfile, unlock)
Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups) Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles)
end end
def group(*args, &blk) def group(*args, &blk)
opts = Hash === args.last ? args.pop.dup : {} options = args.last.is_a?(Hash) ? args.pop.dup : {}
normalize_group_options(opts, args) normalize_group_options(options, args)
@groups.concat args @groups.concat args
if opts["optional"] if options["optional"]
optional_groups = args - @optional_groups optional_groups = args - @optional_groups
@optional_groups.concat optional_groups @optional_groups.concat optional_groups
end end
@ -216,9 +234,9 @@ module Bundler
args.each { @groups.pop } args.each { @groups.pop }
end end
def install_if(*args, &blk) def install_if(*args)
@install_conditionals.concat args @install_conditionals.concat args
blk.call yield
ensure ensure
args.each { @install_conditionals.pop } args.each { @install_conditionals.pop }
end end
@ -250,7 +268,12 @@ module Bundler
private private
def add_git_sources def add_git_sources
return if Bundler.feature_flag.skip_default_git_sources?
git_source(:github) do |repo_name| git_source(:github) do |repo_name|
warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".')
"https://github.com/#{repo_name}.git"
RUBY
# It would be better to use https instead of the git protocol, but this # It would be better to use https instead of the git protocol, but this
# can break deployment of existing locked bundles when switching between # can break deployment of existing locked bundles when switching between
# different versions of Bundler. The change will be made in 2.0, which # different versions of Bundler. The change will be made in 2.0, which
@ -267,23 +290,29 @@ module Bundler
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
# TODO: 2.0 upgrade this setting to the default # TODO: 2.0 upgrade this setting to the default
if Bundler.settings["github.https"] if Bundler.settings["github.https"]
Bundler::SharedHelpers.major_deprecation 2, "The `github.https` setting will be removed"
"https://github.com/#{repo_name}.git" "https://github.com/#{repo_name}.git"
else else
warn_github_source_change(repo_name)
"git://github.com/#{repo_name}.git" "git://github.com/#{repo_name}.git"
end end
end end
# TODO: 2.0 remove this deprecated git source # TODO: 2.0 remove this deprecated git source
git_source(:gist) do |repo_name| git_source(:gist) do |repo_name|
warn_deprecated_git_source(:gist, 'https://gist.github.com/#{repo_name}.git') warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"')
"https://gist.github.com/#{repo_name}.git" "https://gist.github.com/#{repo_name}.git"
end end
# TODO: 2.0 remove this deprecated git source # TODO: 2.0 remove this deprecated git source
git_source(:bitbucket) do |repo_name| git_source(:bitbucket) do |repo_name|
user_name, repo_name = repo_name.split "/" warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip)
warn_deprecated_git_source(:bitbucket, 'https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git') user_name, repo_name = repo_name.split("/")
repo_name ||= user_name
"https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
RUBY
user_name, repo_name = repo_name.split("/")
repo_name ||= user_name repo_name ||= user_name
"https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
end end
@ -308,7 +337,7 @@ module Bundler
end end
def valid_keys def valid_keys
@valid_keys ||= %w(group groups git path glob name branch ref tag require submodules platform platforms type source install_if) @valid_keys ||= VALID_KEYS
end end
def normalize_options(name, version, opts) def normalize_options(name, version, opts)
@ -318,6 +347,9 @@ module Bundler
if name =~ /\s/ if name =~ /\s/
raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace)
end end
if name.empty?
raise GemfileError, %(an empty gem name is not valid)
end
normalize_hash(opts) normalize_hash(opts)
@ -355,7 +387,7 @@ module Bundler
opts["git"] = @git_sources[git_name].call(opts[git_name]) opts["git"] = @git_sources[git_name].call(opts[git_name])
end end
%w(git path).each do |type| %w[git path].each do |type|
next unless param = opts[type] next unless param = opts[type]
if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/
options = opts.merge("name" => name, "version" => $1) options = opts.merge("name" => name, "version" => $1)
@ -377,7 +409,7 @@ module Bundler
normalize_hash(opts) normalize_hash(opts)
groups = groups.map {|group| ":#{group}" }.join(", ") groups = groups.map {|group| ":#{group}" }.join(", ")
validate_keys("group #{groups}", opts, %w(optional)) validate_keys("group #{groups}", opts, %w[optional])
opts["optional"] ||= false opts["optional"] ||= false
end end
@ -390,7 +422,8 @@ module Bundler
raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch)
end end
if invalid_keys.any? return true unless invalid_keys.any?
message = String.new message = String.new
message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} "
message << if invalid_keys.size > 1 message << if invalid_keys.size > 1
@ -403,12 +436,11 @@ module Bundler
message << " You may be able to resolve this by upgrading Bundler to the newest version." message << " You may be able to resolve this by upgrading Bundler to the newest version."
raise InvalidOption, message raise InvalidOption, message
end end
end
def normalize_source(source) def normalize_source(source)
case source case source
when :gemcutter, :rubygems, :rubyforge when :gemcutter, :rubygems, :rubyforge
Bundler::SharedHelpers.major_deprecation "The source :#{source} is deprecated because HTTP " \ Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \
"requests are insecure.\nPlease change your source to 'https://" \ "requests are insecure.\nPlease change your source to 'https://" \
"rubygems.org' if possible, or 'http://rubygems.org' if not." "rubygems.org' if possible, or 'http://rubygems.org' if not."
"http://rubygems.org" "http://rubygems.org"
@ -419,17 +451,20 @@ module Bundler
end end
end end
def check_primary_source_safety(source) def check_primary_source_safety(source_list)
return unless source.rubygems_primary_remotes.any? return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil?
# TODO: 2.0 upgrade from setting to default if Bundler.feature_flag.disable_multisource?
if Bundler.settings[:disable_multisource] msg = "This Gemfile contains multiple primary sources. " \
raise GemfileError, "Warning: this Gemfile contains multiple primary sources. " \
"Each source after the first must include a block to indicate which gems " \ "Each source after the first must include a block to indicate which gems " \
"should come from that source. To downgrade this error to a warning, run " \ "should come from that source"
unless Bundler.feature_flag.bundler_2_mode?
msg += ". To downgrade this error to a warning, run " \
"`bundle config --delete disable_multisource`" "`bundle config --delete disable_multisource`"
end
raise GemfileEvalError, msg
else else
Bundler::SharedHelpers.major_deprecation "Your Gemfile contains multiple primary sources. " \ Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \
"Using `source` more than once without a block is a security risk, and " \ "Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \ "may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source. " \ "a block to indicate which gems should come from the secondary source. " \
@ -438,20 +473,20 @@ module Bundler
end end
end end
def warn_github_source_change(repo_name) def warn_deprecated_git_source(name, replacement, additional_message = nil)
# TODO: 2.0 remove deprecation # TODO: 2.0 remove deprecation
Bundler::SharedHelpers.major_deprecation "The :github option uses the git: protocol, which is not secure. " \ additional_message &&= " #{additional_message}"
"Bundler 2.0 will use the https: protocol, which is secure. Enable this change now by " \ replacement = if replacement.count("\n").zero?
"running `bundle config github.https true`." "{|repo_name| #{replacement} }"
else
"do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end"
end end
def warn_deprecated_git_source(name, repo_string) Bundler::SharedHelpers.major_deprecation 2, <<-EOS
# TODO: 2.0 remove deprecation The :#{name} git source is deprecated, and will be removed in Bundler 2.0.#{additional_message} Add this code to the top of your Gemfile to ensure it continues to work:
Bundler::SharedHelpers.major_deprecation <<-EOS
The :#{name} git source is deprecated, and will be removed in Bundler 2.0. Add this code to your Gemfile to ensure it continues to work: git_source(:#{name}) #{replacement}
git_source(:#{name}) do |repo_name|
"#{repo_string}"
end
EOS EOS
end end
@ -530,7 +565,7 @@ The :#{name} git source is deprecated, and will be removed in Bundler 2.0. Add t
lines = contents.lines.to_a lines = contents.lines.to_a
indent = " # " indent = " # "
indicator = indent.tr("#", ">") indicator = indent.tr("#", ">")
first_line = (line_numer.zero?) first_line = line_numer.zero?
last_line = (line_numer == (lines.count - 1)) last_line = (line_numer == (lines.count - 1))
m << "\n" m << "\n"

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
# used for Creating Specifications from the Gemcutter Endpoint # used for Creating Specifications from the Gemcutter Endpoint
class EndpointSpecification < Gem::Specification class EndpointSpecification < Gem::Specification
@ -9,11 +10,15 @@ module Bundler
attr_accessor :source, :remote, :dependencies attr_accessor :source, :remote, :dependencies
def initialize(name, version, platform, dependencies, metadata = nil) def initialize(name, version, platform, dependencies, metadata = nil)
super()
@name = name @name = name
@version = Gem::Version.create version @version = Gem::Version.create version
@platform = platform @platform = platform
@dependencies = dependencies.map {|dep, reqs| build_dependency(dep, reqs) } @dependencies = dependencies.map {|dep, reqs| build_dependency(dep, reqs) }
@loaded_from = nil
@remote_specification = nil
parse_metadata(metadata) parse_metadata(metadata)
end end
@ -71,6 +76,8 @@ module Bundler
@remote_specification.post_install_message @remote_specification.post_install_message
elsif _local_specification elsif _local_specification
_local_specification.post_install_message _local_specification.post_install_message
else
super
end end
end end
@ -80,6 +87,8 @@ module Bundler
@remote_specification.extensions @remote_specification.extensions
elsif _local_specification elsif _local_specification
_local_specification.extensions _local_specification.extensions
else
super
end end
end end

View file

@ -1,33 +1,21 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/rubygems_integration" require "bundler/rubygems_integration"
require "bundler/source/git/git_proxy" require "bundler/source/git/git_proxy"
module Bundler module Bundler
class Env class Env
def write(io) def self.write(io)
io.write report io.write report
end end
def report(options = {}) def self.report(options = {})
print_gemfile = options.delete(:print_gemfile) { true } print_gemfile = options.delete(:print_gemfile) { true }
print_gemspecs = options.delete(:print_gemspecs) { true } print_gemspecs = options.delete(:print_gemspecs) { true }
out = String.new("## Environment\n\n```\n") out = String.new
out << "Bundler #{Bundler::VERSION}\n" append_formatted_table("Environment", environment, out)
out << "Rubygems #{Gem::VERSION}\n" append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out)
out << "Ruby #{ruby_version}"
out << "GEM_HOME #{ENV["GEM_HOME"]}\n" unless ENV["GEM_HOME"].nil? || ENV["GEM_HOME"].empty?
out << "GEM_PATH #{ENV["GEM_PATH"]}\n" unless ENV["GEM_PATH"] == ENV["GEM_HOME"]
out << "RVM #{ENV["rvm_version"]}\n" if ENV["rvm_version"]
out << "Git #{git_version}\n"
out << "Platform #{Gem::Platform.local}\n"
out << "OpenSSL #{OpenSSL::OPENSSL_VERSION}\n" if defined?(OpenSSL::OPENSSL_VERSION)
%w(rubygems-bundler open_gem).each do |name|
specs = Bundler.rubygems.find_name(name)
out << "#{name} (#{specs.map(&:version).join(",")})\n" unless specs.empty?
end
out << "```\n"
unless Bundler.settings.all.empty? unless Bundler.settings.all.empty?
out << "\n## Bundler settings\n\n```\n" out << "\n## Bundler settings\n\n```\n"
@ -43,9 +31,18 @@ module Bundler
return out unless SharedHelpers.in_bundle? return out unless SharedHelpers.in_bundle?
if print_gemfile if print_gemfile
gemfiles = [Bundler.default_gemfile]
begin
gemfiles = Bundler.definition.gemfiles
rescue GemfileNotFound
nil
end
out << "\n## Gemfile\n" out << "\n## Gemfile\n"
out << "\n### #{Bundler.default_gemfile.relative_path_from(SharedHelpers.pwd)}\n\n" gemfiles.each do |gemfile|
out << "```ruby\n" << read_file(Bundler.default_gemfile).chomp << "\n```\n" out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n"
end
out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n" out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n"
@ -63,9 +60,7 @@ module Bundler
out out
end end
private def self.read_file(filename)
def read_file(filename)
File.read(filename.to_s).strip File.read(filename.to_s).strip
rescue Errno::ENOENT rescue Errno::ENOENT
"<No #{filename} found>" "<No #{filename} found>"
@ -73,22 +68,86 @@ module Bundler
"#{e.class}: #{e.message}" "#{e.class}: #{e.message}"
end end
def ruby_version def self.ruby_version
str = String.new("#{RUBY_VERSION}") str = String.new("#{RUBY_VERSION}")
if RUBY_VERSION < "1.9" if RUBY_VERSION < "1.9"
str << " (#{RUBY_RELEASE_DATE}" str << " (#{RUBY_RELEASE_DATE}"
str << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL str << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
str << ") [#{RUBY_PLATFORM}]\n" str << ") [#{RUBY_PLATFORM}]"
else else
str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]\n" str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]"
end end
end end
def git_version def self.git_version
Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version
rescue Bundler::Source::Git::GitNotInstalledError rescue Bundler::Source::Git::GitNotInstalledError
"not installed" "not installed"
end end
def self.version_of(script)
return "not installed" unless Bundler.which(script)
`#{script} --version`
end
def self.chruby_version
return "not installed" unless Bundler.which("chruby-exec")
`chruby-exec -- chruby --version`.
sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1')
end
def self.environment
out = []
out << ["Bundler", Bundler::VERSION]
out << [" Platforms", Gem.platforms.join(", ")]
out << ["Ruby", ruby_version]
out << [" Full Path", Gem.ruby]
out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname]
out << ["RubyGems", Gem::VERSION]
out << [" Gem Home", ENV.fetch("GEM_HOME") { Gem.dir }]
out << [" Gem Path", ENV.fetch("GEM_PATH") { Gem.path.join(File::PATH_SEPARATOR) }]
out << [" User Path", Gem.user_dir]
out << [" Bin Dir", Gem.bindir]
out << ["OpenSSL"] if defined?(OpenSSL)
out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION)
out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION)
out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE)
out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR)
out << ["Tools"]
out << [" Git", git_version]
out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }]
out << [" rbenv", version_of("rbenv")]
out << [" chruby", chruby_version]
%w[rubygems-bundler open_gem].each do |name|
specs = Bundler.rubygems.find_name(name)
out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
end
if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z}
shebang = File.read(exe).lines.first
shebang.sub!(/^#!\s*/, "")
unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
out << ["Gem.ruby", Gem.ruby]
out << ["bundle #!", shebang]
end
end
out
end
def self.append_formatted_table(title, pairs, out)
return if pairs.empty?
out << "\n" unless out.empty?
out << "## #{title}\n\n```\n"
ljust = pairs.map {|k, _v| k.to_s.length }.max
pairs.each do |k, v|
out << "#{k.to_s.ljust(ljust)} #{v}\n"
end
out << "```\n"
end
private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version
end end
end end

View file

@ -1,12 +1,29 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class EnvironmentPreserver class EnvironmentPreserver
INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze
BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH
BUNDLE_GEMFILE
BUNDLER_ORIG_MANPATH
BUNDLER_VERSION
GEM_HOME
GEM_PATH
MANPATH
PATH
RB_USER_INSTALL
RUBYLIB
RUBYOPT
].map(&:freeze).freeze
BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze
# @param env [ENV] # @param env [ENV]
# @param keys [Array<String>] # @param keys [Array<String>]
def initialize(env, keys) def initialize(env, keys)
@original = env.to_hash @original = env.to_hash
@keys = keys @keys = keys
@prefix = "BUNDLER_ORIG_" @prefix = BUNDLER_PREFIX
end end
# @return [Hash] # @return [Hash]
@ -14,9 +31,10 @@ module Bundler
env = @original.clone env = @original.clone
@keys.each do |key| @keys.each do |key|
value = env[key] value = env[key]
original_value = env[@prefix + key] if !value.nil? && !value.empty?
if !value.nil? && !value.empty? && original_value.nil? env[@prefix + key] ||= value
env[@prefix + key] = value elsif value.nil?
env[@prefix + key] ||= INTENTIONALLY_NIL
end end
end end
env env
@ -27,10 +45,13 @@ module Bundler
env = @original.clone env = @original.clone
@keys.each do |key| @keys.each do |key|
value_original = env[@prefix + key] value_original = env[@prefix + key]
unless value_original.nil? || value_original.empty? next if value_original.nil? || value_original.empty?
if value_original == INTENTIONALLY_NIL
env.delete(key)
else
env[key] = value_original env[key] = value_original
env.delete(@prefix + key)
end end
env.delete(@prefix + key)
end end
env env
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class BundlerError < StandardError class BundlerError < StandardError
def self.status_code(code) def self.status_code(code)

View file

@ -1,22 +1,59 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class FeatureFlag class FeatureFlag
def self.settings_flag(flag, &default) def self.settings_flag(flag, &default)
unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s)
raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key"
end end
define_method("#{flag}?") do
value = Bundler.settings[flag] settings_method("#{flag}?", flag, &default)
end
private_class_method :settings_flag
def self.settings_option(key, &default)
settings_method(key, key, &default)
end
private_class_method :settings_option
def self.settings_method(name, key, &default)
define_method(name) do
value = Bundler.settings[key]
value = instance_eval(&default) if value.nil? && !default.nil? value = instance_eval(&default) if value.nil? && !default.nil?
value value
end end
end end
private_class_method :settings_method
(1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } }
settings_flag(:allow_bundler_dependency_conflicts) { bundler_2_mode? }
settings_flag(:allow_offline_install) { bundler_2_mode? } settings_flag(:allow_offline_install) { bundler_2_mode? }
settings_flag(:auto_clean_without_path) { bundler_2_mode? }
settings_flag(:cache_all) { bundler_2_mode? }
settings_flag(:cache_command_is_package) { bundler_2_mode? }
settings_flag(:console_command) { !bundler_2_mode? }
settings_flag(:default_install_uses_path) { bundler_2_mode? }
settings_flag(:deployment_means_frozen) { bundler_2_mode? }
settings_flag(:disable_multisource) { bundler_2_mode? }
settings_flag(:error_on_stderr) { bundler_2_mode? }
settings_flag(:forget_cli_options) { bundler_2_mode? }
settings_flag(:global_gem_cache) { bundler_2_mode? }
settings_flag(:init_gems_rb) { bundler_2_mode? }
settings_flag(:list_command) { bundler_2_mode? }
settings_flag(:lockfile_uses_separate_rubygems_sources) { bundler_2_mode? }
settings_flag(:only_update_to_newer_versions) { bundler_2_mode? } settings_flag(:only_update_to_newer_versions) { bundler_2_mode? }
settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
settings_flag(:prefer_gems_rb) { bundler_2_mode? }
settings_flag(:print_only_version_number) { bundler_2_mode? }
settings_flag(:setup_makes_kernel_gem_public) { !bundler_2_mode? }
settings_flag(:skip_default_git_sources) { bundler_2_mode? }
settings_flag(:specific_platform) { bundler_2_mode? }
settings_flag(:suppress_install_using_messages) { bundler_2_mode? }
settings_flag(:unlock_source_unlocks_spec) { !bundler_2_mode? }
settings_flag(:update_requires_all_flag) { bundler_2_mode? }
settings_option(:default_cli_command) { bundler_2_mode? ? :cli_help : :install }
def initialize(bundler_version) def initialize(bundler_version)
@bundler_version = Gem::Version.create(bundler_version) @bundler_version = Gem::Version.create(bundler_version)
@ -26,7 +63,5 @@ module Bundler
@bundler_version.segments.first @bundler_version.segments.first
end end
private :major_version private :major_version
class << self; private :settings_flag; end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/vendored_persistent" require "bundler/vendored_persistent"
require "cgi" require "cgi"
require "securerandom" require "securerandom"
@ -237,7 +238,7 @@ module Bundler
Bundler.settings[:ssl_client_cert] Bundler.settings[:ssl_client_cert]
raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
con = Bundler::Persistent::Net::HTTP::Persistent.new "bundler", :ENV con = PersistentHTTP.new "bundler", :ENV
if gem_proxy = Bundler.rubygems.configuration[:http_proxy] if gem_proxy = Bundler.rubygems.configuration[:http_proxy]
con.proxy = URI.parse(gem_proxy) if gem_proxy != :no_proxy con.proxy = URI.parse(gem_proxy) if gem_proxy != :no_proxy
end end
@ -248,8 +249,11 @@ module Bundler
con.cert_store = bundler_cert_store con.cert_store = bundler_cert_store
end end
if Bundler.settings[:ssl_client_cert] ssl_client_cert = Bundler.settings[:ssl_client_cert] ||
pem = File.read(Bundler.settings[:ssl_client_cert]) (Bundler.rubygems.configuration.ssl_client_cert if
Bundler.rubygems.configuration.respond_to?(:ssl_client_cert))
if ssl_client_cert
pem = File.read(ssl_client_cert)
con.cert = OpenSSL::X509::Certificate.new(pem) con.cert = OpenSSL::X509::Certificate.new(pem)
con.key = OpenSSL::PKey::RSA.new(pem) con.key = OpenSSL::PKey::RSA.new(pem)
end end
@ -273,16 +277,19 @@ module Bundler
Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
Bundler::Persistent::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH
].freeze ].freeze
def bundler_cert_store def bundler_cert_store
store = OpenSSL::X509::Store.new store = OpenSSL::X509::Store.new
if Bundler.settings[:ssl_ca_cert] ssl_ca_cert = Bundler.settings[:ssl_ca_cert] ||
if File.directory? Bundler.settings[:ssl_ca_cert] (Bundler.rubygems.configuration.ssl_ca_cert if
store.add_path Bundler.settings[:ssl_ca_cert] Bundler.rubygems.configuration.respond_to?(:ssl_ca_cert))
if ssl_ca_cert
if File.directory? ssl_ca_cert
store.add_path ssl_ca_cert
else else
store.add_file Bundler.settings[:ssl_ca_cert] store.add_file ssl_ca_cert
end end
else else
store.set_default_paths store.set_default_paths

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Fetcher class Fetcher
class Base class Base

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/fetcher/base" require "bundler/fetcher/base"
require "bundler/worker" require "bundler/worker"
@ -61,7 +62,7 @@ module Bundler
compact_index_request :fetch_spec compact_index_request :fetch_spec
def available? def available?
return nil unless md5_available? return nil unless SharedHelpers.md5_available?
user_home = Bundler.user_home user_home = Bundler.user_home
return nil unless user_home.directory? && user_home.writable? return nil unless user_home.directory? && user_home.writable?
# Read info file checksums out of /versions, so we can know if gems are up to date # Read info file checksums out of /versions, so we can know if gems are up to date
@ -120,16 +121,6 @@ module Bundler
Net::HTTPNotModified.new(nil, nil, nil) Net::HTTPNotModified.new(nil, nil, nil)
end end
end end
def md5_available?
require "openssl"
OpenSSL::Digest::MD5.digest("")
true
rescue LoadError
true
rescue OpenSSL::Digest::DigestError
false
end
end end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/fetcher/base" require "bundler/fetcher/base"
require "cgi" require "cgi"
@ -6,7 +7,7 @@ module Bundler
class Fetcher class Fetcher
class Dependency < Base class Dependency < Base
def available? def available?
fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri)
rescue NetworkDownError => e rescue NetworkDownError => e
raise HTTPError, e.message raise HTTPError, e.message
rescue AuthenticationRequiredError rescue AuthenticationRequiredError

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Fetcher class Fetcher
class Downloader class Downloader

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/fetcher/base" require "bundler/fetcher/base"
require "rubygems/remote_fetcher" require "rubygems/remote_fetcher"

View file

@ -1,5 +1,6 @@
# encoding: utf-8 # encoding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require "cgi" require "cgi"
require "bundler/vendored_thor" require "bundler/vendored_thor"
@ -92,7 +93,7 @@ module Bundler
#{e.backtrace && e.backtrace.join("\n ").chomp} #{e.backtrace && e.backtrace.join("\n ").chomp}
``` ```
#{Bundler::Env.new.report} #{Bundler::Env.report}
--- TEMPLATE END ---------------------------------------------------------------- --- TEMPLATE END ----------------------------------------------------------------
EOS EOS
@ -119,6 +120,8 @@ module Bundler
def self.with_friendly_errors def self.with_friendly_errors
yield yield
rescue SignalException
raise
rescue Exception => e rescue Exception => e
FriendlyErrors.log_error(e) FriendlyErrors.log_error(e)
exit FriendlyErrors.exit_status(e) exit FriendlyErrors.exit_status(e)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/vendored_thor" unless defined?(Thor) require "bundler/vendored_thor" unless defined?(Thor)
require "bundler" require "bundler"
@ -50,8 +51,8 @@ module Bundler
install_gem(built_gem_path, :local) install_gem(built_gem_path, :local)
end end
desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to Rubygems\n" \ desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \
"To prevent publishing in Rubygems use `gem_push=no rake release`" "To prevent publishing in RubyGems use `gem_push=no rake release`"
task "release", [:remote] => ["build", "release:guard_clean", task "release", [:remote] => ["build", "release:guard_clean",
"release:source_control_push", "release:rubygem_push"] do "release:source_control_push", "release:rubygem_push"] do
end end
@ -92,18 +93,14 @@ module Bundler
protected protected
def rubygem_push(path) def rubygem_push(path)
allowed_push_host = nil
gem_command = "gem push '#{path}'" gem_command = "gem push '#{path}'"
gem_command += " --key #{gem_key}" if gem_key gem_command += " --key #{gem_key}" if gem_key
if @gemspec.respond_to?(:metadata)
allowed_push_host = @gemspec.metadata["allowed_push_host"]
gem_command += " --host #{allowed_push_host}" if allowed_push_host gem_command += " --host #{allowed_push_host}" if allowed_push_host
end
unless allowed_push_host || Bundler.user_home.join(".gem/credentials").file? unless allowed_push_host || Bundler.user_home.join(".gem/credentials").file?
raise "Your rubygems.org credentials aren't set. Run `gem push` to set them." raise "Your rubygems.org credentials aren't set. Run `gem push` to set them."
end end
sh(gem_command) sh(gem_command)
Bundler.ui.confirm "Pushed #{name} #{version} to #{allowed_push_host ? allowed_push_host : "rubygems.org."}" Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}"
end end
def built_gem_path def built_gem_path
@ -116,6 +113,18 @@ module Bundler
Bundler.ui.confirm "Pushed git commits and tags." Bundler.ui.confirm "Pushed git commits and tags."
end end
def allowed_push_host
@gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata)
end
def gem_push_host
env_rubygems_host = ENV["RUBYGEMS_HOST"]
env_rubygems_host = nil if
env_rubygems_host && env_rubygems_host.empty?
allowed_push_host || env_rubygems_host || "rubygems.org"
end
def perform_git_push(options = "") def perform_git_push(options = "")
cmd = "git push #{options}" cmd = "git push #{options}"
out, code = sh_with_code(cmd) out, code = sh_with_code(cmd)
@ -187,7 +196,7 @@ module Bundler
end end
def gem_push? def gem_push?
!%w(n no nil false off 0).include?(ENV["gem_push"].to_s.downcase) !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase)
end end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
module GemHelpers module GemHelpers
GENERIC_CACHE = {} # rubocop:disable MutableConstant GENERIC_CACHE = {} # rubocop:disable MutableConstant

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "rubygems/remote_fetcher" require "rubygems/remote_fetcher"
module Bundler module Bundler

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "rake/clean" require "rake/clean"
CLOBBER.include "pkg" CLOBBER.include "pkg"

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
# This class contains all of the logic for determining the next version of a # This class contains all of the logic for determining the next version of a
# Gem to update to based on the requested level (patch, minor, major). # Gem to update to based on the requested level (patch, minor, major).

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Gemdeps class Gemdeps
def initialize(runtime) def initialize(runtime)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "set" require "set"
module Bundler module Bundler
class Graph class Graph

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "set" require "set"
module Bundler module Bundler
@ -111,6 +112,13 @@ module Bundler
spec_sets.values.each(&blk) spec_sets.values.each(&blk)
end end
sources.each {|s| s.each(&blk) } sources.each {|s| s.each(&blk) }
self
end
def spec_names
names = specs.keys + sources.map(&:spec_names)
names.uniq!
names
end end
# returns a list of the dependencies # returns a list of the dependencies
@ -191,14 +199,6 @@ module Bundler
end end
end end
wants_prerelease = dependency.requirement.prerelease?
wants_prerelease ||= base && base.any? {|base_spec| base_spec.version.prerelease? }
only_prerelease = specs.all? {|spec| spec.version.prerelease? }
unless wants_prerelease || only_prerelease
found.reject! {|spec| spec.version.prerelease? }
end
found found
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Injector class Injector
def self.inject(new_deps, options = {}) def self.inject(new_deps, options = {})
@ -12,13 +13,13 @@ module Bundler
end end
def inject(gemfile_path, lockfile_path) def inject(gemfile_path, lockfile_path)
if Bundler.settings[:frozen] if Bundler.frozen?
# ensure the lock and Gemfile are synced # ensure the lock and Gemfile are synced
Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
# temporarily remove frozen while we inject
frozen = Bundler.settings.delete(:frozen)
end end
# temporarily unfreeze
Bundler.settings.temporary(:deployment => false, :frozen => false) do
# evaluate the Gemfile we have now # evaluate the Gemfile we have now
builder = Dsl.new builder = Dsl.new
builder.eval_gemfile(gemfile_path) builder.eval_gemfile(gemfile_path)
@ -27,7 +28,7 @@ module Bundler
@new_deps -= builder.dependencies @new_deps -= builder.dependencies
# add new deps to the end of the in-memory Gemfile # add new deps to the end of the in-memory Gemfile
# Set conservative versioining to false because we want to let the resolver resolve the version first # Set conservative versioning to false because we want to let the resolver resolve the version first
builder.eval_gemfile("injected gems", build_gem_lines(false)) if @new_deps.any? builder.eval_gemfile("injected gems", build_gem_lines(false)) if @new_deps.any?
# resolve to see if the new deps broke anything # resolve to see if the new deps broke anything
@ -40,10 +41,12 @@ module Bundler
# since we resolved successfully, write out the lockfile # since we resolved successfully, write out the lockfile
@definition.lock(Bundler.default_lockfile) @definition.lock(Bundler.default_lockfile)
# invalidate the cached Bundler.definition
Bundler.reset_paths!
# return an array of the deps that we added # return an array of the deps that we added
return @new_deps @new_deps
ensure end
Bundler.settings[:frozen] = "1" if frozen
end end
private private

View file

@ -1,4 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/compatibility_guard"
# Allows for declaring a Gemfile inline in a ruby script, optionally installing # Allows for declaring a Gemfile inline in a ruby script, optionally installing
# any gems that aren't already installed on the user's system. # any gems that aren't already installed on the user's system.
# #
@ -39,7 +42,7 @@ def gemfile(install = false, options = {}, &gemfile)
def Bundler.root def Bundler.root
Bundler::SharedHelpers.pwd.expand_path Bundler::SharedHelpers.pwd.expand_path
end end
ENV["BUNDLE_GEMFILE"] = "Gemfile" Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
builder = Bundler::Dsl.new builder = Bundler::Dsl.new
@ -50,12 +53,7 @@ def gemfile(install = false, options = {}, &gemfile)
definition.validate_runtime! definition.validate_runtime!
missing_specs = proc do missing_specs = proc do
begin definition.missing_specs?
!definition.missing_specs.empty?
rescue Bundler::GemNotFound, Bundler::GitError
definition.instance_variable_set(:@index, nil)
true
end
end end
Bundler.ui = ui if install Bundler.ui = ui if install

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "erb" require "erb"
require "rubygems/dependency_installer" require "rubygems/dependency_installer"
require "bundler/worker" require "bundler/worker"
@ -33,25 +34,26 @@ module Bundler
# Runs the install procedures for a specific Gemfile. # Runs the install procedures for a specific Gemfile.
# #
# Firstly, this method will check to see if Bundler.bundle_path exists # Firstly, this method will check to see if `Bundler.bundle_path` exists
# and if not then will create it. This is usually the location of gems # and if not then Bundler will create the directory. This is usually the same
# on the system, be it RVM or at a system path. # location as RubyGems which typically is the `~/.gem` directory
# unless other specified.
# #
# Secondly, it checks if Bundler has been configured to be "frozen" # Secondly, it checks if Bundler has been configured to be "frozen".
# Frozen ensures that the Gemfile and the Gemfile.lock file are matching. # Frozen ensures that the Gemfile and the Gemfile.lock file are matching.
# This stops a situation where a developer may update the Gemfile but may not run # This stops a situation where a developer may update the Gemfile but may not run
# `bundle install`, which leads to the Gemfile.lock file not being correctly updated. # `bundle install`, which leads to the Gemfile.lock file not being correctly updated.
# If this file is not correctly updated then any other developer running # If this file is not correctly updated then any other developer running
# `bundle install` will potentially not install the correct gems. # `bundle install` will potentially not install the correct gems.
# #
# Thirdly, Bundler checks if there are any dependencies specified in the Gemfile using # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile.
# Bundler::Environment#dependencies. If there are no dependencies specified then # If there are no dependencies specified then Bundler returns a warning message stating
# Bundler returns a warning message stating so and this method returns. # so and this method returns.
# #
# Fourthly, Bundler checks if the default lockfile (Gemfile.lock) exists, and if so # Fourthly, Bundler checks if the Gemfile.lock exists, and if so
# then proceeds to set up a definition based on the default gemfile (Gemfile) and the # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock.
# default lock file (Gemfile.lock). However, this is not the case if the platform is different # During this step Bundler will also download information about any new gems
# to that which is specified in Gemfile.lock, or if there are any missing specs for the gems. # that are not in the Gemfile.lock and resolve any dependencies if needed.
# #
# Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote.
# This then leads into the gems being installed, along with stubs for their executables, # This then leads into the gems being installed, along with stubs for their executables,
@ -61,11 +63,14 @@ module Bundler
# Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time
# that a user runs `bundle install` they will receive any updates from this process. # that a user runs `bundle install` they will receive any updates from this process.
# #
# Finally: TODO add documentation for how the standalone process works. # Finally, if the user has specified the standalone flag, Bundler will generate the needed
# require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more
# information.
def run(options) def run(options)
create_bundle_path create_bundle_path
if Bundler.settings[:frozen] ProcessLock.lock do
if Bundler.frozen?
@definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
end end
@ -75,13 +80,20 @@ module Bundler
return return
end end
resolve_if_need(options) if resolve_if_needed(options)
ensure_specs_are_compatible! ensure_specs_are_compatible!
warn_on_incompatible_bundler_deps
load_plugins
options.delete(:jobs)
else
options[:jobs] = 1 # to avoid the overhead of Bundler::Worker
end
install(options) install(options)
lock unless Bundler.settings[:frozen] lock unless Bundler.frozen?
Standalone.new(options[:standalone], @definition).generate if options[:standalone] Standalone.new(options[:standalone], @definition).generate if options[:standalone]
end end
end
def generate_bundler_executable_stubs(spec, options = {}) def generate_bundler_executable_stubs(spec, options = {})
if options[:binstubs_cmd] && spec.executables.empty? if options[:binstubs_cmd] && spec.executables.empty?
@ -101,15 +113,21 @@ module Bundler
end end
# double-assignment to avoid warnings about variables that will be used by ERB # double-assignment to avoid warnings about variables that will be used by ERB
bin_path = bin_path = Bundler.bin_path bin_path = Bundler.bin_path
template = template = File.read(File.expand_path("../templates/Executable", __FILE__)) bin_path = bin_path
relative_gemfile_path = relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path)
ruby_command = ruby_command = Thor::Util.ruby_command relative_gemfile_path = relative_gemfile_path
ruby_command = Thor::Util.ruby_command
ruby_command = ruby_command
template_path = File.expand_path("../templates/Executable", __FILE__)
if spec.name == "bundler"
template_path += ".bundler"
spec.executables = %(bundle)
end
template = File.read(template_path)
exists = [] exists = []
spec.executables.each do |executable| spec.executables.each do |executable|
next if executable == "bundle"
binstub_path = "#{bin_path}/#{executable}" binstub_path = "#{bin_path}/#{executable}"
if File.exist?(binstub_path) && !options[:force] if File.exist?(binstub_path) && !options[:force]
exists << executable exists << executable
@ -139,13 +157,19 @@ module Bundler
def generate_standalone_bundler_executable_stubs(spec) def generate_standalone_bundler_executable_stubs(spec)
# double-assignment to avoid warnings about variables that will be used by ERB # double-assignment to avoid warnings about variables that will be used by ERB
bin_path = Bundler.bin_path bin_path = Bundler.bin_path
standalone_path = standalone_path = Bundler.root.join(Bundler.settings[:path]).relative_path_from(bin_path) unless path = Bundler.settings[:path]
raise "Can't standalone without an explicit path set"
end
standalone_path = Bundler.root.join(path).relative_path_from(bin_path)
standalone_path = standalone_path
template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__)) template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__))
ruby_command = ruby_command = Thor::Util.ruby_command ruby_command = Thor::Util.ruby_command
ruby_command = ruby_command
spec.executables.each do |executable| spec.executables.each do |executable|
next if executable == "bundle" next if executable == "bundle"
executable_path = executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path)
executable_path = executable_path
File.open "#{bin_path}/#{executable}", "w", 0o755 do |f| File.open "#{bin_path}/#{executable}", "w", 0o755 do |f|
f.puts ERB.new(template, nil, "-").result(binding) f.puts ERB.new(template, nil, "-").result(binding)
end end
@ -159,13 +183,32 @@ module Bundler
# that said, it's a rare situation (other than rake), and parallel # that said, it's a rare situation (other than rake), and parallel
# installation is SO MUCH FASTER. so we let people opt in. # installation is SO MUCH FASTER. so we let people opt in.
def install(options) def install(options)
Bundler.rubygems.load_plugins
force = options["force"] force = options["force"]
jobs = 1 jobs = options.delete(:jobs) do
jobs = [Bundler.settings[:jobs].to_i - 1, 1].max if can_install_in_parallel? if can_install_in_parallel?
[Bundler.settings[:jobs].to_i - 1, 1].max
else
1
end
end
install_in_parallel jobs, options[:standalone], force install_in_parallel jobs, options[:standalone], force
end end
def load_plugins
Bundler.rubygems.load_plugins
requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
path_plugin_files = requested_path_gems.map do |spec|
begin
Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
rescue TypeError
error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
raise Gem::InvalidSpecificationException, error_message
end
end.flatten
Bundler.rubygems.load_plugin_files(path_plugin_files)
end
def ensure_specs_are_compatible! def ensure_specs_are_compatible!
system_ruby = Bundler::RubyVersion.system system_ruby = Bundler::RubyVersion.system
rubygems_version = Gem::Version.create(Gem::VERSION) rubygems_version = Gem::Version.create(Gem::VERSION)
@ -184,12 +227,28 @@ module Bundler
end end
end end
def warn_on_incompatible_bundler_deps
bundler_version = Gem::Version.create(Bundler::VERSION)
@definition.specs.each do |spec|
spec.dependencies.each do |dep|
next if dep.type == :development
next unless dep.name == "bundler".freeze
next if dep.requirement.satisfied_by?(bundler_version)
Bundler.ui.warn "#{spec.name} (#{spec.version}) has dependency" \
" #{SharedHelpers.pretty_dependency(dep)}" \
", which is unsatisfied by the current bundler version #{VERSION}" \
", so the dependency is being ignored"
end
end
end
def can_install_in_parallel? def can_install_in_parallel?
if Bundler.rubygems.provides?(">= 2.1.0") if Bundler.rubygems.provides?(">= 2.1.0")
true true
else else
Bundler.ui.warn "Rubygems #{Gem::VERSION} is not threadsafe, so your "\ Bundler.ui.warn "RubyGems #{Gem::VERSION} is not threadsafe, so your "\
"gems will be installed one at a time. Upgrade to Rubygems 2.1.0 " \ "gems will be installed one at a time. Upgrade to RubyGems 2.1.0 " \
"or higher to enable parallel gem installation." "or higher to enable parallel gem installation."
false false
end end
@ -207,23 +266,18 @@ module Bundler
Bundler.mkdir_p(p) Bundler.mkdir_p(p)
end unless Bundler.bundle_path.exist? end unless Bundler.bundle_path.exist?
rescue Errno::EEXIST rescue Errno::EEXIST
raise PathError, "Could not install to path `#{Bundler.settings[:path]}` " \ raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \
"because a file already exists at that path. Either remove or rename the file so the directory can be created." "because a file already exists at that path. Either remove or rename the file so the directory can be created."
end end
def resolve_if_need(options) # returns whether or not a re-resolve was needed
if !options["update"] && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? def resolve_if_needed(options)
local = Bundler.ui.silence do if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file?
begin return false if @definition.nothing_changed? && !@definition.missing_specs?
tmpdef = Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, nil)
true unless tmpdef.new_platform? || tmpdef.missing_dependencies.any?
rescue BundlerError
end
end
end end
return if local
options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely!
true
end end
def lock(opts = {}) def lock(opts = {})

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class GemInstaller class GemInstaller
attr_reader :spec, :standalone, :worker, :force, :installer attr_reader :spec, :standalone, :worker, :force, :installer
@ -65,6 +66,7 @@ module Bundler
end end
def generate_executable_stubs def generate_executable_stubs
return if Bundler.feature_flag.forget_cli_options?
return if Bundler.settings[:inline] return if Bundler.settings[:inline]
if Bundler.settings[:bin] && standalone if Bundler.settings[:bin] && standalone
installer.generate_standalone_bundler_executable_stubs(spec) installer.generate_standalone_bundler_executable_stubs(spec)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/worker" require "bundler/worker"
require "bundler/installer/gem_installer" require "bundler/installer/gem_installer"
@ -77,11 +78,6 @@ module Bundler
new(*args).call new(*args).call
end end
# Returns max number of threads machine can handle with a min of 1
def self.max_threads
[Bundler.settings[:jobs].to_i - 1, 1].max
end
attr_reader :size attr_reader :size
def initialize(installer, all_specs, size, standalone, force) def initialize(installer, all_specs, size, standalone, force)
@ -99,49 +95,19 @@ module Bundler
require "bundler/gem_remote_fetcher" if RUBY_VERSION < "1.9" require "bundler/gem_remote_fetcher" if RUBY_VERSION < "1.9"
check_for_corrupt_lockfile check_for_corrupt_lockfile
enqueue_specs
process_specs until @specs.all?(&:installed?) || @specs.any?(&:failed?) if @size > 1
install_with_worker
else
install_serially
end
handle_error if @specs.any?(&:failed?) handle_error if @specs.any?(&:failed?)
@specs @specs
ensure ensure
worker_pool && worker_pool.stop worker_pool && worker_pool.stop
end end
def worker_pool
@worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda { |spec_install, worker_num|
gem_installer = Bundler::GemInstaller.new(
spec_install.spec, @installer, @standalone, worker_num, @force
)
success, message = gem_installer.install_from_spec
if success && !message.nil?
spec_install.post_install_message = message
elsif !success
spec_install.state = :failed
spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
end
spec_install
}
end
# Dequeue a spec and save its post-install message and then enqueue the
# remaining specs.
# Some specs might've had to wait til this spec was installed to be
# processed so the call to `enqueue_specs` is important after every
# dequeue.
def process_specs
spec = worker_pool.deq
spec.state = :installed unless spec.failed?
enqueue_specs
end
def handle_error
errors = @specs.select(&:failed?).map(&:error)
if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) }
raise exception
end
raise Bundler::InstallError, errors.map(&:to_s).join("\n\n")
end
def check_for_corrupt_lockfile def check_for_corrupt_lockfile
missing_dependencies = @specs.map do |s| missing_dependencies = @specs.map do |s|
[ [
@ -167,6 +133,71 @@ module Bundler
Bundler.ui.warn(warning.join("\n")) Bundler.ui.warn(warning.join("\n"))
end end
private
def install_with_worker
enqueue_specs
process_specs until finished_installing?
end
def install_serially
until finished_installing?
raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?)
spec_install.state = :enqueued
do_install(spec_install, 0)
end
end
def worker_pool
@worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda { |spec_install, worker_num|
do_install(spec_install, worker_num)
}
end
def do_install(spec_install, worker_num)
gem_installer = Bundler::GemInstaller.new(
spec_install.spec, @installer, @standalone, worker_num, @force
)
success, message = begin
gem_installer.install_from_spec
rescue => e
raise e, "#{e}\n\n#{require_tree_for_spec(spec_install.spec)}"
end
if success
spec_install.state = :installed
spec_install.post_install_message = message unless message.nil?
else
spec_install.state = :failed
spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
end
spec_install
end
# Dequeue a spec and save its post-install message and then enqueue the
# remaining specs.
# Some specs might've had to wait til this spec was installed to be
# processed so the call to `enqueue_specs` is important after every
# dequeue.
def process_specs
worker_pool.deq
enqueue_specs
end
def finished_installing?
@specs.all? do |spec|
return true if spec.failed?
spec.installed?
end
end
def handle_error
errors = @specs.select(&:failed?).map(&:error)
if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) }
raise exception
end
raise Bundler::InstallError, errors.map(&:to_s).join("\n\n")
end
def require_tree_for_spec(spec) def require_tree_for_spec(spec)
tree = @spec_set.what_required(spec) tree = @spec_set.what_required(spec)
t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n") t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n")

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Standalone class Standalone
def initialize(groups, definition) def initialize(groups, definition)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "uri" require "uri"
require "bundler/match_platform" require "bundler/match_platform"
@ -68,7 +69,7 @@ module Bundler
end end
def __materialize__ def __materialize__
search_object = Bundler.settings[:specific_platform] || Bundler.settings[:force_ruby_platform] ? self : Dependency.new(name, version) search_object = Bundler.feature_flag.specific_platform? || Bundler.settings[:force_ruby_platform] ? self : Dependency.new(name, version)
@specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name
source.gemspec.tap {|s| s.source = source } source.gemspec.tap {|s| s.source = source }
else else

View file

@ -0,0 +1,95 @@
# frozen_string_literal: true
module Bundler
class LockfileGenerator
attr_reader :definition
attr_reader :out
# @private
def initialize(definition)
@definition = definition
@out = String.new
end
def self.generate(definition)
new(definition).generate!
end
def generate!
add_sources
add_platforms
add_dependencies
add_locked_ruby_version
add_bundled_with
out
end
private
def add_sources
definition.send(:sources).lock_sources.each_with_index do |source, idx|
out << "\n" unless idx.zero?
# Add the source header
out << source.to_lock
# Find all specs for this source
specs = definition.resolve.select {|s| source.can_lock?(s) }
add_specs(specs)
end
end
def add_specs(specs)
# This needs to be sorted by full name so that
# gems with the same name, but different platform
# are ordered consistently
specs.sort_by(&:full_name).each do |spec|
next if spec.name == "bundler".freeze
out << spec.to_lock
end
end
def add_platforms
add_section("PLATFORMS", definition.platforms)
end
def add_dependencies
out << "\nDEPENDENCIES\n"
handled = []
definition.dependencies.sort_by(&:to_s).each do |dep|
next if handled.include?(dep.name)
out << dep.to_lock
handled << dep.name
end
end
def add_locked_ruby_version
return unless locked_ruby_version = definition.locked_ruby_version
add_section("RUBY VERSION", locked_ruby_version.to_s)
end
def add_bundled_with
add_section("BUNDLED WITH", definition.locked_bundler_version.to_s)
end
def add_section(name, value)
out << "\n#{name}\n"
case value
when Array
value.map(&:to_s).sort.each do |val|
out << " #{val}\n"
end
when Hash
value.to_a.sort_by {|k, _| k.to_s }.each do |key, val|
out << " #{key}: #{val}\n"
end
when String
out << " #{value}\n"
else
raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile"
end
end
end
end

View file

@ -90,7 +90,7 @@ module Bundler
send("parse_#{@state}", line) send("parse_#{@state}", line)
end end
end end
@sources << @rubygems_aggregate @sources << @rubygems_aggregate unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
@specs = @specs.values.sort_by(&:identifier) @specs = @specs.values.sort_by(&:identifier)
warn_for_outdated_bundler_version warn_for_outdated_bundler_version
rescue ArgumentError => e rescue ArgumentError => e
@ -141,10 +141,16 @@ module Bundler
@sources << @current_source @sources << @current_source
end end
when GEM when GEM
if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
@opts["remotes"] = @opts.delete("remote")
@current_source = TYPES[@type].from_lock(@opts)
@sources << @current_source
else
Array(@opts["remote"]).each do |url| Array(@opts["remote"]).each do |url|
@rubygems_aggregate.add_remote(url) @rubygems_aggregate.add_remote(url)
end end
@current_source = @rubygems_aggregate @current_source = @rubygems_aggregate
end
when PLUGIN when PLUGIN
@current_source = Plugin.source_from_lock(@opts) @current_source = Plugin.source_from_lock(@opts)
@sources << @current_source @sources << @current_source

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/gem_helpers" require "bundler/gem_helpers"
module Bundler module Bundler

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "socket" require "socket"
module Bundler module Bundler
@ -37,7 +38,7 @@ module Bundler
mirror = if config.all? mirror = if config.all?
@all @all
else else
(@mirrors[config.uri] = @mirrors[config.uri] || Mirror.new) @mirrors[config.uri] ||= Mirror.new
end end
config.update_mirror(mirror) config.update_mirror(mirror)
end end
@ -45,7 +46,9 @@ module Bundler
private private
def fetch_valid_mirror_for(uri) def fetch_valid_mirror_for(uri)
mirror = (@mirrors[URI(uri.to_s.downcase)] || @mirrors[URI(uri.to_s).host] || Mirror.new(uri)).validate!(@prober) downcased = uri.to_s.downcase
mirror = @mirrors[downcased] || @mirrors[URI(downcased).host] || Mirror.new(uri)
mirror.validate!(@prober)
mirror = Mirror.new(uri) unless mirror.valid? mirror = Mirror.new(uri) unless mirror.valid?
mirror mirror
end end
@ -117,7 +120,7 @@ module Bundler
def initialize(config_line, value) def initialize(config_line, value)
uri, fallback = uri, fallback =
config_line.match(%r{^mirror\.(all|.+?)(\.fallback_timeout)?\/?$}).captures config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures
@fallback = !fallback.nil? @fallback = !fallback.nil?
@all = false @all = false
if uri == "all" if uri == "all"

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/plugin/api" require "bundler/plugin/api"
module Bundler module Bundler

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "uri" require "uri"
require "digest/sha1"
module Bundler module Bundler
module Plugin module Plugin
@ -271,7 +271,7 @@ module Bundler
end end
def uri_hash def uri_hash
Digest::SHA1.hexdigest(uri) SharedHelpers.digest(:SHA1).hexdigest(uri)
end end
# Note: Do not override if you don't know what you are doing. # Note: Do not override if you don't know what you are doing.
@ -293,6 +293,13 @@ module Bundler
def bundler_plugin_api_source? def bundler_plugin_api_source?
true true
end end
# @private
# This API on source might not be stable, and for now we expect plugins
# to download all specs in `#specs`, so we implement the method for
# compatibility purposes and leave it undocumented (and don't support)
# overriding it)
def double_check_for(*); end
end end
end end
end end

View file

@ -13,7 +13,7 @@ module Bundler
def install(names, options) def install(names, options)
version = options[:version] || [">= 0"] version = options[:version] || [">= 0"]
Bundler.settings.temporary(:lockfile_uses_separate_rubygems_sources => false, :disable_multisource => false) do
if options[:git] if options[:git]
install_git(names, version, options) install_git(names, version, options)
else else
@ -21,6 +21,7 @@ module Bundler
install_rubygems(names, version, sources) install_rubygems(names, version, sources)
end end
end end
end
# Installs the plugin from Definition object created by limited parsing of # Installs the plugin from Definition object created by limited parsing of
# Gemfile searching for plugins to be installed # Gemfile searching for plugins to be installed

View file

@ -5,13 +5,6 @@ module Bundler
# approptiate options to be used with Source classes for plugin installation # approptiate options to be used with Source classes for plugin installation
module Plugin module Plugin
class SourceList < Bundler::SourceList class SourceList < Bundler::SourceList
def initialize
@path_sources = []
@git_sources = []
@rubygems_aggregate = Plugin::Installer::Rubygems.new
@rubygems_sources = []
end
def add_git_source(options = {}) def add_git_source(options = {})
add_source_to_list Plugin::Installer::Git.new(options), git_sources add_source_to_list Plugin::Installer::Git.new(options), git_sources
end end
@ -21,7 +14,13 @@ module Bundler
end end
def all_sources def all_sources
path_sources + git_sources + rubygems_sources path_sources + git_sources + rubygems_sources + [metadata_source]
end
private
def rubygems_aggregate_class
Plugin::Installer::Rubygems
end end
end end
end end

View file

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Bundler
class ProcessLock
def self.lock(bundle_path = Bundler.bundle_path)
lock_file_path = File.join(bundle_path, "bundler.lock")
has_lock = false
File.open(lock_file_path, "w") do |f|
f.flock(File::LOCK_EX)
has_lock = true
yield
f.flock(File::LOCK_UN)
end
rescue Errno::EACCES, Errno::ENOLCK
# In the case the user does not have access to
# create the lock file or is using NFS where
# locks are not available we skip locking.
yield
ensure
FileUtils.rm_f(lock_file_path) if has_lock
end
end
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
# Psych could be a gem, so try to ask for it # Psych could be a gem, so try to ask for it
begin begin
gem "psych" gem "psych"
@ -25,3 +26,12 @@ module Bundler
YamlLibrarySyntaxError = ::ArgumentError YamlLibrarySyntaxError = ::ArgumentError
end end
end end
require "bundler/deprecate"
begin
Bundler::Deprecate.skip_during do
require "rubygems/safe_yaml"
end
rescue LoadError
# it's OK if the file isn't there
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "uri" require "uri"
module Bundler module Bundler

View file

@ -1,178 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Resolver class Resolver
require "bundler/vendored_molinillo" require "bundler/vendored_molinillo"
require "bundler/resolver/spec_group"
class Molinillo::VersionConflict
def printable_dep(dep)
if dep.is_a?(Bundler::Dependency)
DepProxy.new(dep, dep.platforms.join(", ")).to_s.strip
else
dep.to_s
end
end
def message
conflicts.sort.reduce(String.new) do |o, (name, conflict)|
o << %(\nBundler could not find compatible versions for gem "#{name}":\n)
if conflict.locked_requirement
o << %( In snapshot (#{Bundler.default_lockfile.basename}):\n)
o << %( #{printable_dep(conflict.locked_requirement)}\n)
o << %(\n)
end
o << %( In Gemfile:\n)
trees = conflict.requirement_trees
maximal = 1.upto(trees.size).map do |size|
trees.map(&:last).flatten(1).combination(size).to_a
end.flatten(1).select do |deps|
Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
end.min_by(&:size)
trees.reject! {|t| !maximal.include?(t.last) } if maximal
o << trees.sort_by {|t| t.reverse.map(&:name) }.map do |tree|
t = String.new
depth = 2
tree.each do |req|
t << " " * depth << req.to_s
unless tree.last == req
if spec = conflict.activated_by_name[req.name]
t << %( was resolved to #{spec.version}, which)
end
t << %( depends on)
end
t << %(\n)
depth += 1
end
t
end.join("\n")
if name == "bundler"
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new Bundler::VERSION)
end
if name == "bundler" && other_bundler_required
o << "\n"
o << "This Gemfile requires a different version of Bundler.\n"
o << "Perhaps you need to update Bundler by running `gem install bundler`?\n"
end
if conflict.locked_requirement
o << "\n"
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
elsif !conflict.existing
o << "\n"
if conflict.requirement_trees.first.size > 1
o << "Could not find gem '#{conflict.requirement}', which is required by "
o << "gem '#{conflict.requirement_trees.first[-2]}', in any of the sources."
else
o << "Could not find gem '#{conflict.requirement}' in any of the sources\n"
end
end
o
end.strip
end
end
class SpecGroup < Array
include GemHelpers
attr_reader :activated
def initialize(a)
super
@required_by = []
@activated_platforms = []
@dependencies = nil
@specs = Hash.new do |specs, platform|
specs[platform] = select_best_platform_match(self, platform)
end
end
def initialize_copy(o)
super
@activated_platforms = o.activated.dup
end
def to_specs
@activated_platforms.map do |p|
next unless s = @specs[p]
lazy_spec = LazySpecification.new(name, version, s.platform, source)
lazy_spec.dependencies.replace s.dependencies
lazy_spec
end.compact
end
def activate_platform!(platform)
return unless for?(platform)
return if @activated_platforms.include?(platform)
@activated_platforms << platform
end
def name
@name ||= first.name
end
def version
@version ||= first.version
end
def source
@source ||= first.source
end
def for?(platform)
spec = @specs[platform]
!spec.nil?
end
def to_s
"#{name} (#{version})"
end
def dependencies_for_activated_platforms
dependencies = @activated_platforms.map {|p| __dependencies[p] }
metadata_dependencies = @activated_platforms.map do |platform|
metadata_dependencies(@specs[platform], platform)
end
dependencies.concat(metadata_dependencies).flatten
end
def platforms_for_dependency_named(dependency)
__dependencies.select {|_, deps| deps.map(&:name).include? dependency }.keys
end
private
def __dependencies
@dependencies = Hash.new do |dependencies, platform|
dependencies[platform] = []
if spec = @specs[platform]
spec.dependencies.each do |dep|
next if dep.type == :development
dependencies[platform] << DepProxy.new(dep, platform)
end
end
dependencies[platform]
end
end
def metadata_dependencies(spec, platform)
return [] unless spec
# Only allow endpoint specifications since they won't hit the network to
# fetch the full gemspec when calling required_ruby_version
return [] if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification)
dependencies = []
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("ruby\0", spec.required_ruby_version), platform)
end
if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("rubygems\0", spec.required_rubygems_version), platform)
end
dependencies
end
end
# Figures out the best possible configuration of gems that satisfies # Figures out the best possible configuration of gems that satisfies
# the list of passed dependencies and any child dependencies without # the list of passed dependencies and any child dependencies without
@ -206,16 +37,22 @@ module Bundler
additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
@platforms = platforms @platforms = platforms
@gem_version_promoter = gem_version_promoter @gem_version_promoter = gem_version_promoter
@allow_bundler_dependency_conflicts = Bundler.feature_flag.allow_bundler_dependency_conflicts?
@lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
end end
def start(requirements) def start(requirements)
@prerelease_specified = {}
requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? }
verify_gemfile_dependencies_are_found!(requirements) verify_gemfile_dependencies_are_found!(requirements)
dg = @resolver.resolve(requirements, @base_dg) dg = @resolver.resolve(requirements, @base_dg)
dg.map(&:payload). dg.map(&:payload).
reject {|sg| sg.name.end_with?("\0") }. reject {|sg| sg.name.end_with?("\0") }.
map(&:to_specs).flatten map(&:to_specs).flatten
rescue Molinillo::VersionConflict => e rescue Molinillo::VersionConflict => e
raise VersionConflict.new(e.conflicts.keys.uniq, e.message) message = version_conflict_message(e)
raise VersionConflict.new(e.conflicts.keys.uniq, message)
rescue Molinillo::CircularDependencyError => e rescue Molinillo::CircularDependencyError => e
names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" } names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" }
raise CyclicDependencyError, "Your bundle requires gems that depend" \ raise CyclicDependencyError, "Your bundle requires gems that depend" \
@ -266,6 +103,14 @@ module Bundler
search = @search_for[dependency] ||= begin search = @search_for[dependency] ||= begin
index = index_for(dependency) index = index_for(dependency)
results = index.search(dependency, @base[dependency.name]) results = index.search(dependency, @base[dependency.name])
unless @prerelease_specified[dependency.name]
# Move prereleases to the beginning of the list, so they're considered
# last during resolution.
pre, results = results.partition {|spec| spec.version.prerelease? }
results = pre + results
end
if vertex = @base_dg.vertex_named(dependency.name) if vertex = @base_dg.vertex_named(dependency.name)
locked_requirement = vertex.payload.requirement locked_requirement = vertex.payload.requirement
end end
@ -281,7 +126,9 @@ module Bundler
end end
nested.reduce([]) do |groups, (version, specs)| nested.reduce([]) do |groups, (version, specs)|
next groups if locked_requirement && !locked_requirement.satisfied_by?(version) next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
groups << SpecGroup.new(specs) spec_group = SpecGroup.new(specs)
spec_group.ignores_bundler_dependencies = @allow_bundler_dependency_conflicts
groups << spec_group
end end
else else
[] []
@ -298,7 +145,20 @@ module Bundler
end end
def index_for(dependency) def index_for(dependency)
@source_requirements[dependency.name] || @index source = @source_requirements[dependency.name]
if source
source.specs
elsif @lockfile_uses_separate_rubygems_sources
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
end
else
@index
end
end end
def name_for(dependency) def name_for(dependency)
@ -319,23 +179,53 @@ module Bundler
def requirement_satisfied_by?(requirement, activated, spec) def requirement_satisfied_by?(requirement, activated, spec)
return false unless requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) return false unless requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
if spec.version.prerelease? && !requirement.prerelease? && search_for(requirement).any? {|sg| !sg.version.prerelease? }
vertex = activated.vertex_named(spec.name)
return false if vertex.requirements.none?(&:prerelease?)
end
spec.activate_platform!(requirement.__platform) if !@platforms || @platforms.include?(requirement.__platform) spec.activate_platform!(requirement.__platform) if !@platforms || @platforms.include?(requirement.__platform)
true true
end end
def relevant_sources_for_vertex(vertex)
if vertex.root?
[@source_requirements[vertex.name]]
elsif @lockfile_uses_separate_rubygems_sources
vertex.recursive_predecessors.map do |v|
@source_requirements[v.name]
end << @source_requirements[:default]
end
end
def sort_dependencies(dependencies, activated, conflicts) def sort_dependencies(dependencies, activated, conflicts)
dependencies.sort_by do |dependency| dependencies.sort_by do |dependency|
dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
name = name_for(dependency) name = name_for(dependency)
vertex = activated.vertex_named(name)
[ [
@base_dg.vertex_named(name) ? 0 : 1, @base_dg.vertex_named(name) ? 0 : 1,
activated.vertex_named(name).payload ? 0 : 1, vertex.payload ? 0 : 1,
vertex.root? ? 0 : 1,
amount_constrained(dependency), amount_constrained(dependency),
conflicts[name] ? 0 : 1, conflicts[name] ? 0 : 1,
activated.vertex_named(name).payload ? 0 : search_for(dependency).count, vertex.payload ? 0 : search_for(dependency).count,
self.class.platform_sort_key(dependency.__platform),
] ]
end end
end end
# Sort platforms from most general to most specific
def self.sort_platforms(platforms)
platforms.sort_by do |platform|
platform_sort_key(platform)
end
end
def self.platform_sort_key(platform)
return ["", "", ""] if Gem::Platform::RUBY == platform
platform.to_a.map {|part| part || "" }
end
private private
# returns an integer \in (-\infty, 0] # returns an integer \in (-\infty, 0]
@ -364,32 +254,34 @@ module Bundler
def verify_gemfile_dependencies_are_found!(requirements) def verify_gemfile_dependencies_are_found!(requirements)
requirements.each do |requirement| requirements.each do |requirement|
next if requirement.name == "bundler"
next unless search_for(requirement).empty?
if (base = @base[requirement.name]) && !base.empty?
version = base.first.version
message = "You have requested:\n" \
" #{requirement.name} #{requirement.requirement}\n\n" \
"The bundle currently has #{requirement.name} locked at #{version}.\n" \
"Try running `bundle update #{requirement.name}`\n\n" \
"If you are updating multiple gems in your Gemfile at once,\n" \
"try passing them all to `bundle update`"
elsif requirement.source
name = requirement.name name = requirement.name
specs = @source_requirements[name][name] next if name == "bundler"
versions_with_platforms = specs.map {|s| [s.version, s.platform] } next unless search_for(requirement).empty?
message = String.new("Could not find gem '#{requirement}' in #{requirement.source}.\n")
message << if versions_with_platforms.any?
"Source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}"
else
"Source does not contain any versions of '#{requirement}'"
end
else
cache_message = begin cache_message = begin
" or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
rescue GemfileNotFound rescue GemfileNotFound
nil nil
end end
if (base = @base[name]) && !base.empty?
version = base.first.version
message = "You have requested:\n" \
" #{name} #{requirement.requirement}\n\n" \
"The bundle currently has #{name} locked at #{version}.\n" \
"Try running `bundle update #{name}`\n\n" \
"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]
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?
"The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}"
else
"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 '#{requirement}' in any of the gem sources " \
"listed in your Gemfile#{cache_message}." "listed in your Gemfile#{cache_message}."
end end
@ -402,9 +294,76 @@ module Bundler
version = vwp.first version = vwp.first
platform = vwp.last platform = vwp.last
version_platform_str = String.new(version.to_s) version_platform_str = String.new(version.to_s)
version_platform_str << " #{platform}" unless platform.nil? version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY
version_platform_str
end end
version_platform_strs.join(", ") version_platform_strs.join(", ")
end end
def version_conflict_message(e)
e.message_with_trees(
:solver_name => "Bundler",
:possibility_type => "gem",
:reduce_trees => lambda do |trees|
maximal = 1.upto(trees.size).map do |size|
trees.map(&:last).flatten(1).combination(size).to_a
end.flatten(1).select do |deps|
Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
end.min_by(&:size)
trees.reject! {|t| !maximal.include?(t.last) } if maximal
trees = trees.sort_by {|t| t.flatten.map(&:to_s) }
trees.uniq! {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
trees.sort_by {|t| t.reverse.map(&:name) }
end,
:printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) },
:additional_message_for_conflict => lambda do |o, name, conflict|
if name == "bundler"
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new Bundler::VERSION)
end
if name == "bundler" && other_bundler_required
o << "\n"
o << "This Gemfile requires a different version of Bundler.\n"
o << "Perhaps you need to update Bundler by running `gem install bundler`?\n"
end
if conflict.locked_requirement
o << "\n"
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
elsif !conflict.existing
o << "\n"
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
[]
end.compact.map(&:to_s).uniq.sort
o << "Could not find gem '#{SharedHelpers.pretty_dependency(conflict.requirement)}'"
if conflict.requirement_trees.first.size > 1
o << ", which is required by "
o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
end
o << " "
o << if relevant_sources.empty?
"in any of the sources.\n"
else
"in any of the relevant sources:\n #{relevant_sources * "\n "}\n"
end
end
end,
:version_for_spec => lambda {|spec| spec.version }
)
end
end end
end end

View file

@ -0,0 +1,111 @@
# frozen_string_literal: true
module Bundler
class Resolver
class SpecGroup
include GemHelpers
attr_accessor :name, :version, :source
attr_accessor :ignores_bundler_dependencies
def initialize(all_specs)
raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first
@name = exemplary_spec.name
@version = exemplary_spec.version
@source = exemplary_spec.source
@required_by = []
@activated_platforms = []
@dependencies = nil
@specs = Hash.new do |specs, platform|
specs[platform] = select_best_platform_match(all_specs, platform)
end
@ignores_bundler_dependencies = true
end
def to_specs
@activated_platforms.map do |p|
next unless s = @specs[p]
lazy_spec = LazySpecification.new(name, version, s.platform, source)
lazy_spec.dependencies.replace s.dependencies
lazy_spec
end.compact
end
def activate_platform!(platform)
return unless for?(platform)
return if @activated_platforms.include?(platform)
@activated_platforms << platform
end
def for?(platform)
spec = @specs[platform]
!spec.nil?
end
def to_s
@to_s ||= "#{name} (#{version})"
end
def dependencies_for_activated_platforms
dependencies = @activated_platforms.map {|p| __dependencies[p] }
metadata_dependencies = @activated_platforms.map do |platform|
metadata_dependencies(@specs[platform], platform)
end
dependencies.concat(metadata_dependencies).flatten
end
def platforms_for_dependency_named(dependency)
__dependencies.select {|_, deps| deps.map(&:name).include? dependency }.keys
end
def ==(other)
return unless other.is_a?(SpecGroup)
name == other.name &&
version == other.version &&
source == other.source
end
def eql?(other)
name.eql?(other.name) &&
version.eql?(other.version) &&
source.eql?(other.source)
end
def hash
to_s.hash ^ source.hash
end
private
def __dependencies
@dependencies = Hash.new do |dependencies, platform|
dependencies[platform] = []
if spec = @specs[platform]
spec.dependencies.each do |dep|
next if dep.type == :development
next if @ignores_bundler_dependencies && dep.name == "bundler".freeze
dependencies[platform] << DepProxy.new(dep, platform)
end
end
dependencies[platform]
end
end
def metadata_dependencies(spec, platform)
return [] unless spec
# Only allow endpoint specifications since they won't hit the network to
# fetch the full gemspec when calling required_ruby_version
return [] if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification)
dependencies = []
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("ruby\0", spec.required_ruby_version), platform)
end
if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("rubygems\0", spec.required_rubygems_version), platform)
end
dependencies
end
end
end
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
# General purpose class for retrying code that may fail # General purpose class for retrying code that may fail
class Retry class Retry

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
module RubyDsl module RubyDsl
def ruby(*ruby_version) def ruby(*ruby_version)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class RubyVersion class RubyVersion
attr_reader :versions, attr_reader :versions,

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "pathname" require "pathname"
if defined?(Gem::QuickLoader) if defined?(Gem::QuickLoader)
@ -14,7 +15,7 @@ begin
# shouldn't be deferred. # shouldn't be deferred.
require "rubygems/source" require "rubygems/source"
rescue LoadError rescue LoadError
# Not available before Rubygems 2.0.0, ignore # Not available before RubyGems 2.0.0, ignore
nil nil
end end
@ -135,7 +136,7 @@ module Gem
end end
class Dependency class Dependency
attr_accessor :source, :groups attr_accessor :source, :groups, :all_sources
alias_method :eql?, :== alias_method :eql?, :==
@ -146,7 +147,7 @@ module Gem
end end
def to_yaml_properties def to_yaml_properties
instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) }
end end
def to_lock def to_lock
@ -158,7 +159,7 @@ module Gem
out out
end end
# Backport of performance enhancement added to Rubygems 1.4 # Backport of performance enhancement added to RubyGems 1.4
def matches_spec?(spec) def matches_spec?(spec)
# name can be a Regexp, so use === # name can be a Regexp, so use ===
return false unless name === spec.name return false unless name === spec.name

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "rubygems/installer" require "rubygems/installer"
module Bundler module Bundler
@ -17,6 +18,28 @@ module Bundler
super && validate_bundler_checksum(options[:bundler_expected_checksum]) super && validate_bundler_checksum(options[:bundler_expected_checksum])
end end
def build_extensions
extension_cache_path = options[:bundler_extension_cache_path]
return super unless extension_cache_path && extension_dir = Bundler.rubygems.spec_extension_dir(spec)
extension_dir = Pathname.new(extension_dir)
build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?)
if build_complete && !options[:force]
SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath)
SharedHelpers.filesystem_access(extension_cache_path) do
FileUtils.cp_r extension_cache_path, spec.extension_dir
end
else
super
if extension_dir.directory? # not made for gems without extensions
SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath)
SharedHelpers.filesystem_access(extension_cache_path) do
FileUtils.cp_r extension_dir, extension_cache_path
end
end
end
end
private private
def validate_bundler_checksum(checksum) def validate_bundler_checksum(checksum)
@ -25,7 +48,7 @@ module Bundler
return true unless source = @package.instance_variable_get(:@gem) return true unless source = @package.instance_variable_get(:@gem)
return true unless source.respond_to?(:with_read_io) return true unless source.respond_to?(:with_read_io)
digest = source.with_read_io do |io| digest = source.with_read_io do |io|
digest = Digest::SHA256.new digest = SharedHelpers.digest(:SHA256).new
digest << io.read(16_384) until io.eof? digest << io.read(16_384) until io.eof?
io.rewind io.rewind
send(checksum_type(checksum), digest) send(checksum_type(checksum), digest)

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "monitor" require "monitor"
require "rubygems" require "rubygems"
require "rubygems/config_file" require "rubygems/config_file"
@ -84,6 +85,19 @@ module Bundler
spec.respond_to?(:default_gem?) && spec.default_gem? spec.respond_to?(:default_gem?) && spec.default_gem?
end end
def spec_matches_for_glob(spec, glob)
return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob)
spec.load_paths.map do |lp|
Dir["#{lp}/#{glob}#{suffix_pattern}"]
end.flatten(1)
end
def spec_extension_dir(spec)
return unless spec.respond_to?(:extension_dir)
spec.extension_dir
end
def stub_set_spec(stub, spec) def stub_set_spec(stub, spec)
stub.instance_variable_set(:@spec, spec) stub.instance_variable_set(:@spec, spec)
end end
@ -158,6 +172,10 @@ module Bundler
Gem.post_reset_hooks Gem.post_reset_hooks
end end
def suffix_pattern
Gem.suffix_pattern
end
def gem_cache def gem_cache
gem_path.map {|p| File.expand_path("cache", p) } gem_path.map {|p| File.expand_path("cache", p) }
end end
@ -165,7 +183,7 @@ module Bundler
def spec_cache_dirs def spec_cache_dirs
@spec_cache_dirs ||= begin @spec_cache_dirs ||= begin
dirs = gem_path.map {|dir| File.join(dir, "specifications") } dirs = gem_path.map {|dir| File.join(dir, "specifications") }
dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in Rubygems 2.0.3 or earlier dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier
dirs.uniq.select {|dir| File.directory? dir } dirs.uniq.select {|dir| File.directory? dir }
end end
end end
@ -179,7 +197,7 @@ module Bundler
end end
def repository_subdirectories def repository_subdirectories
%w(cache doc gems specifications) %w[cache doc gems specifications]
end end
def clear_paths def clear_paths
@ -190,8 +208,12 @@ module Bundler
Gem.bin_path(gem, bin, ver) Gem.bin_path(gem, bin, ver)
end end
def path_separator
File::PATH_SEPARATOR
end
def preserve_paths def preserve_paths
# this is a no-op outside of Rubygems 1.8 # this is a no-op outside of RubyGems 1.8
yield yield
end end
@ -212,6 +234,10 @@ module Bundler
Gem.load_plugins if Gem.respond_to?(:load_plugins) Gem.load_plugins if Gem.respond_to?(:load_plugins)
end end
def load_plugin_files(files)
Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files)
end
def ui=(obj) def ui=(obj)
Gem::DefaultUserInteraction.ui = obj Gem::DefaultUserInteraction.ui = obj
end end
@ -233,9 +259,9 @@ module Bundler
{} # if we can't download them, there aren't any {} # if we can't download them, there aren't any
end end
# TODO: This is for older versions of Rubygems... should we support the # TODO: This is for older versions of RubyGems... should we support the
# X-Gemfile-Source header on these old versions? # X-Gemfile-Source header on these old versions?
# Maybe the newer implementation will work on older Rubygems? # Maybe the newer implementation will work on older RubyGems?
# It seems difficult to keep this implementation and still send the header. # It seems difficult to keep this implementation and still send the header.
def fetch_all_remote_specs(remote) def fetch_all_remote_specs(remote)
old_sources = Bundler.rubygems.sources old_sources = Bundler.rubygems.sources
@ -273,6 +299,7 @@ module Bundler
def spec_from_gem(path, policy = nil) def spec_from_gem(path, policy = nil)
require "rubygems/security" require "rubygems/security"
require "bundler/psyched_yaml"
gem_from_path(path, security_policies[policy]).spec gem_from_path(path, security_policies[policy]).spec
rescue Gem::Package::FormatError rescue Gem::Package::FormatError
raise GemspecError, "Could not read gem at #{path}. It may be corrupted." raise GemspecError, "Could not read gem at #{path}. It may be corrupted."
@ -306,7 +333,7 @@ module Bundler
end end
def security_policy_keys def security_policy_keys
%w(High Medium Low AlmostNo No).map {|level| "#{level}Security" } %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" }
end end
def security_policies def security_policies
@ -377,9 +404,8 @@ module Bundler
raise e raise e
end end
# TODO: delete this in 2.0, it's a backwards compatibility shim # backwards compatibility shim, see https://github.com/bundler/bundler/issues/5102
# see https://github.com/bundler/bundler/issues/5102 kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public?
kernel_class.send(:public, :gem)
end end
end end
@ -434,9 +460,9 @@ module Bundler
raise Gem::Exception, "no default executable for #{spec.full_name}" unless exec_name ||= spec.default_executable raise Gem::Exception, "no default executable for #{spec.full_name}" unless exec_name ||= spec.default_executable
unless spec.name == name unless spec.name == gem_name
Bundler::SharedHelpers.major_deprecation \ Bundler::SharedHelpers.major_deprecation 2,
"Bundler is using a binstub that was created for a different gem.\n" \ "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \
"You should run `bundle binstub #{gem_name}` " \ "You should run `bundle binstub #{gem_name}` " \
"to work around a system/bundle conflict." "to work around a system/bundle conflict."
end end
@ -476,7 +502,7 @@ module Bundler
redefine_method(gem_class, :refresh) {} redefine_method(gem_class, :refresh) {}
end end
# Replace or hook into Rubygems to provide a bundlerized view # Replace or hook into RubyGems to provide a bundlerized view
# of the world. # of the world.
def replace_entrypoints(specs) def replace_entrypoints(specs)
specs_by_name = specs.reduce({}) do |h, s| specs_by_name = specs.reduce({}) do |h, s|
@ -492,8 +518,8 @@ module Bundler
Gem.clear_paths Gem.clear_paths
end end
# This backports the correct segment generation code from Rubygems 1.4+ # This backports the correct segment generation code from RubyGems 1.4+
# by monkeypatching it into the method in Rubygems 1.3.6 and 1.3.7. # by monkeypatching it into the method in RubyGems 1.3.6 and 1.3.7.
def backport_segment_generation def backport_segment_generation
redefine_method(Gem::Version, :segments) do redefine_method(Gem::Version, :segments) do
@segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s| @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
@ -512,7 +538,7 @@ module Bundler
end end
# This backports base_dir which replaces installation path # This backports base_dir which replaces installation path
# Rubygems 1.8+ # RubyGems 1.8+
def backport_base_dir def backport_base_dir
redefine_method(Gem::Specification, :base_dir) do redefine_method(Gem::Specification, :base_dir) do
return Gem.dir unless loaded_from return Gem.dir unless loaded_from
@ -581,7 +607,7 @@ module Bundler
end end
end end
# Rubygems 1.4 through 1.6 # RubyGems 1.4 through 1.6
class Legacy < RubygemsIntegration class Legacy < RubygemsIntegration
def initialize def initialize
super super
@ -592,7 +618,7 @@ module Bundler
end end
def stub_rubygems(specs) def stub_rubygems(specs)
# Rubygems versions lower than 1.7 use SourceIndex#from_gems_in # RubyGems versions lower than 1.7 use SourceIndex#from_gems_in
source_index_class = (class << Gem::SourceIndex; self; end) source_index_class = (class << Gem::SourceIndex; self; end)
redefine_method(source_index_class, :from_gems_in) do |*args| redefine_method(source_index_class, :from_gems_in) do |*args|
Gem::SourceIndex.new.tap do |source_index| Gem::SourceIndex.new.tap do |source_index|
@ -624,7 +650,7 @@ module Bundler
end end
end end
# Rubygems versions 1.3.6 and 1.3.7 # RubyGems versions 1.3.6 and 1.3.7
class Ancient < Legacy class Ancient < Legacy
def initialize def initialize
super super
@ -632,7 +658,7 @@ module Bundler
end end
end end
# Rubygems 1.7 # RubyGems 1.7
class Transitional < Legacy class Transitional < Legacy
def stub_rubygems(specs) def stub_rubygems(specs)
stub_source_index(specs) stub_source_index(specs)
@ -646,7 +672,7 @@ module Bundler
end end
end end
# Rubygems 1.8.5-1.8.19 # RubyGems 1.8.5-1.8.19
class Modern < RubygemsIntegration class Modern < RubygemsIntegration
def stub_rubygems(specs) def stub_rubygems(specs)
Gem::Specification.all = specs Gem::Specification.all = specs
@ -667,9 +693,9 @@ module Bundler
end end
end end
# Rubygems 1.8.0 to 1.8.4 # RubyGems 1.8.0 to 1.8.4
class AlmostModern < Modern class AlmostModern < Modern
# Rubygems [>= 1.8.0, < 1.8.5] has a bug that changes Gem.dir whenever # RubyGems [>= 1.8.0, < 1.8.5] has a bug that changes Gem.dir whenever
# you call Gem::Installer#install with an :install_dir set. We have to # you call Gem::Installer#install with an :install_dir set. We have to
# change it back for our sudo mode to work. # change it back for our sudo mode to work.
def preserve_paths def preserve_paths
@ -680,9 +706,9 @@ module Bundler
end end
end end
# Rubygems 1.8.20+ # RubyGems 1.8.20+
class MoreModern < Modern class MoreModern < Modern
# Rubygems 1.8.20 and adds the skip_validation parameter, so that's # RubyGems 1.8.20 and adds the skip_validation parameter, so that's
# when we start passing it through. # when we start passing it through.
def build(spec, skip_validation = false) def build(spec, skip_validation = false)
require "rubygems/builder" require "rubygems/builder"
@ -690,7 +716,7 @@ module Bundler
end end
end end
# Rubygems 2.0 # RubyGems 2.0
class Future < RubygemsIntegration class Future < RubygemsIntegration
def stub_rubygems(specs) def stub_rubygems(specs)
Gem::Specification.all = specs Gem::Specification.all = specs
@ -767,6 +793,10 @@ module Bundler
def install_with_build_args(args) def install_with_build_args(args)
yield yield
end end
def path_separator
Gem.path_separator
end
end end
# RubyGems 2.1.0 # RubyGems 2.1.0
@ -855,7 +885,7 @@ module Bundler
RubygemsIntegration::Transitional.new RubygemsIntegration::Transitional.new
elsif RubygemsIntegration.provides?(">= 1.4.0") elsif RubygemsIntegration.provides?(">= 1.4.0")
RubygemsIntegration::Legacy.new RubygemsIntegration::Legacy.new
else # Rubygems 1.3.6 and 1.3.7 else # RubyGems 1.3.6 and 1.3.7
RubygemsIntegration::Ancient.new RubygemsIntegration::Ancient.new
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require "digest/sha1"
module Bundler module Bundler
class Runtime class Runtime
@ -11,7 +10,7 @@ module Bundler
end end
def setup(*groups) def setup(*groups)
@definition.ensure_equivalent_gemfile_and_lockfile if Bundler.settings[:frozen] @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen?
groups.map!(&:to_sym) groups.map!(&:to_sym)
@ -262,9 +261,6 @@ module Bundler
end end
def setup_manpath def setup_manpath
# Store original MANPATH for restoration later in with_clean_env()
ENV["BUNDLER_ORIG_MANPATH"] = ENV["MANPATH"]
# Add man/ subdirectories from activated bundles to MANPATH for man(1) # Add man/ subdirectories from activated bundles to MANPATH for man(1)
manuals = $LOAD_PATH.map do |path| manuals = $LOAD_PATH.map do |path|
man_subdir = path.sub(/lib$/, "man") man_subdir = path.sub(/lib$/, "man")
@ -272,7 +268,7 @@ module Bundler
end.compact end.compact
return if manuals.empty? return if manuals.empty?
ENV["MANPATH"] = manuals.concat( Bundler::SharedHelpers.set_env "MANPATH", manuals.concat(
ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR)
).uniq.join(File::PATH_SEPARATOR) ).uniq.join(File::PATH_SEPARATOR)
end end

View file

@ -1,60 +1,89 @@
# frozen_string_literal: true # frozen_string_literal: true
require "uri" require "uri"
module Bundler module Bundler
class Settings class Settings
autoload :Mirror, "bundler/mirror" autoload :Mirror, "bundler/mirror"
autoload :Mirrors, "bundler/mirror" autoload :Mirrors, "bundler/mirror"
autoload :Validator, "bundler/settings/validator"
BOOL_KEYS = %w( BOOL_KEYS = %w[
allow_bundler_dependency_conflicts
allow_deployment_source_credential_changes
allow_offline_install allow_offline_install
auto_clean_without_path
auto_install auto_install
cache_all cache_all
cache_all_platforms cache_all_platforms
cache_command_is_package
console_command
default_install_uses_path
deployment
deployment_means_frozen
disable_checksum_validation disable_checksum_validation
disable_exec_load disable_exec_load
disable_local_branch_check disable_local_branch_check
disable_multisource
disable_shared_gems disable_shared_gems
disable_version_check disable_version_check
error_on_stderr
force_ruby_platform force_ruby_platform
forget_cli_options
frozen frozen
gem.coc gem.coc
gem.mit gem.mit
global_gem_cache
ignore_messages ignore_messages
init_gems_rb
list_command
lockfile_uses_separate_rubygems_sources
major_deprecations major_deprecations
no_install no_install
no_prune no_prune
only_update_to_newer_versions only_update_to_newer_versions
path.system
plugins plugins
prefer_gems_rb
print_only_version_number
setup_makes_kernel_gem_public
silence_root_warning silence_root_warning
).freeze skip_default_git_sources
specific_platform
suppress_install_using_messages
unlock_source_unlocks_spec
update_requires_all_flag
].freeze
NUMBER_KEYS = %w( NUMBER_KEYS = %w[
redirect redirect
retry retry
ssl_verify_mode ssl_verify_mode
timeout timeout
).freeze ].freeze
ARRAY_KEYS = %w[
with
without
].freeze
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
:disable_version_check => true,
:redirect => 5, :redirect => 5,
:retry => 3, :retry => 3,
:timeout => 10, :timeout => 10,
}.freeze }.freeze
attr_accessor :cli_flags_given
def initialize(root = nil) def initialize(root = nil)
@root = root @root = root
@local_config = load_config(local_config_file) @local_config = load_config(local_config_file)
@global_config = load_config(global_config_file) @global_config = load_config(global_config_file)
@cli_flags_given = false
@temporary = {} @temporary = {}
end end
def [](name) def [](name)
key = key_for(name) key = key_for(name)
value = @temporary.fetch(name) do value = @temporary.fetch(key) do
@local_config.fetch(key) do @local_config.fetch(key) do
ENV.fetch(key) do ENV.fetch(key) do
@global_config.fetch(key) do @global_config.fetch(key) do
@ -65,48 +94,59 @@ module Bundler
converted_value(value, name) converted_value(value, name)
end end
def []=(key, value) def set_command_option(key, value)
if cli_flags_given if Bundler.feature_flag.forget_cli_options?
temporary(key => value)
value
else
command = if value.nil? command = if value.nil?
"bundle config --delete #{key}" "bundle config --delete #{key}"
else else
"bundle config #{key} #{Array(value).join(":")}" "bundle config #{key} #{Array(value).join(":")}"
end end
Bundler::SharedHelpers.major_deprecation \ Bundler::SharedHelpers.major_deprecation 2,\
"flags passed to commands " \ "flags passed to commands " \
"will no longer be automatically remembered. Instead please set flags " \ "will no longer be automatically remembered. Instead please set flags " \
"you want remembered between commands using `bundle config " \ "you want remembered between commands using `bundle config " \
"<setting name> <setting value>`, i.e. `#{command}`" "<setting name> <setting value>`, i.e. `#{command}`"
set_local(key, value)
end end
end
def set_command_option_if_given(key, value)
return if value.nil?
set_command_option(key, value)
end
def set_local(key, value)
local_config_file || raise(GemfileNotFound, "Could not locate Gemfile") local_config_file || raise(GemfileNotFound, "Could not locate Gemfile")
set_key(key, value, @local_config, local_config_file) set_key(key, value, @local_config, local_config_file)
end end
alias_method :set_local, :[]=
def temporary(update) def temporary(update)
existing = Hash[update.map {|k, _| [k, @temporary[k]] }] existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }]
@temporary.update(update) update.each do |k, v|
set_key(k, v, @temporary, nil)
end
return unless block_given? return unless block_given?
begin begin
yield yield
ensure ensure
existing.each {|k, v| v.nil? ? @temporary.delete(k) : @temporary[k] = v } existing.each {|k, v| set_key(k, v, @temporary, nil) }
end end
end end
def delete(key)
@local_config.delete(key_for(key))
end
def set_global(key, value) def set_global(key, value)
set_key(key, value, @global_config, global_config_file) set_key(key, value, @global_config, global_config_file)
end end
def all def all
env_keys = ENV.keys.select {|k| k =~ /BUNDLE_.*/ } env_keys = ENV.keys.grep(/\ABUNDLE_.+/)
keys = @global_config.keys | @local_config.keys | env_keys keys = @temporary.keys | @global_config.keys | @local_config.keys | env_keys
keys.map do |key| keys.map do |key|
key.sub(/^BUNDLE_/, "").gsub(/__/, ".").downcase key.sub(/^BUNDLE_/, "").gsub(/__/, ".").downcase
@ -132,7 +172,7 @@ module Bundler
def gem_mirrors def gem_mirrors
all.inject(Mirrors.new) do |mirrors, k| all.inject(Mirrors.new) do |mirrors, k|
mirrors.parse(k, self[k]) if k =~ /^mirror\./ mirrors.parse(k, self[k]) if k.start_with?("mirror.")
mirrors mirrors
end end
end end
@ -140,6 +180,7 @@ module Bundler
def locations(key) def locations(key)
key = key_for(key) key = key_for(key)
locations = {} locations = {}
locations[:temporary] = @temporary[key] if @temporary.key?(key)
locations[:local] = @local_config[key] if @local_config.key?(key) locations[:local] = @local_config[key] if @local_config.key?(key)
locations[:env] = ENV[key] if ENV[key] locations[:env] = ENV[key] if ENV[key]
locations[:global] = @global_config[key] if @global_config.key?(key) locations[:global] = @global_config[key] if @global_config.key?(key)
@ -151,6 +192,11 @@ module Bundler
key = key_for(exposed_key) key = key_for(exposed_key)
locations = [] locations = []
if @temporary.key?(key)
locations << "Set for the current command: #{converted_value(@temporary[key], exposed_key).inspect}"
end
if @local_config.key?(key) if @local_config.key?(key)
locations << "Set for your local app (#{local_config_file}): #{converted_value(@local_config[key], exposed_key).inspect}" locations << "Set for your local app (#{local_config_file}): #{converted_value(@local_config[key], exposed_key).inspect}"
end end
@ -167,37 +213,56 @@ module Bundler
locations locations
end end
def without=(array) # for legacy reasons, the ruby scope isnt appended when the setting comes from ENV or the global config,
set_array(:without, array) # nor do we respect :disable_shared_gems
end
def with=(array)
set_array(:with, array)
end
def without
get_array(:without)
end
def with
get_array(:with)
end
# @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"]
def path def path
key = key_for(:path) key = key_for(:path)
path = ENV[key] || @global_config[key] path = ENV[key] || @global_config[key]
return path if path && !@local_config.key?(key) if path && !@temporary.key?(key) && !@local_config.key?(key)
return Path.new(path, false, false, false)
end
if path = self[:path] system_path = self["path.system"] || (self[:disable_shared_gems] == false)
"#{path}/#{Bundler.ruby_scope}" Path.new(self[:path], true, system_path, Bundler.feature_flag.default_install_uses_path?)
else end
Bundler.rubygems.gem_dir
Path = Struct.new(:explicit_path, :append_ruby_scope, :system_path, :default_install_uses_path) do
def path
path = base_path
path = File.join(path, Bundler.ruby_scope) if append_ruby_scope && !use_system_gems?
path
end
def use_system_gems?
return true if system_path
return false if explicit_path
!default_install_uses_path
end
def base_path
path = explicit_path
path ||= ".bundle" unless use_system_gems?
path ||= Bundler.rubygems.gem_dir
path
end
def validate!
return unless explicit_path && system_path
path = Bundler.settings.pretty_values_for(:path)
path.unshift(nil, "path:") unless path.empty?
system_path = Bundler.settings.pretty_values_for("path.system")
system_path.unshift(nil, "path.system:") unless system_path.empty?
disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems)
disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty?
raise InvalidOption,
"Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}"
end end
end end
def allow_sudo? def allow_sudo?
!@local_config.key?(key_for(:path)) key = key_for(:path)
path_configured = @temporary.key?(key) || @local_config.key?(key)
!path_configured
end end
def ignore_config? def ignore_config?
@ -205,14 +270,17 @@ module Bundler
end end
def app_cache_path def app_cache_path
@app_cache_path ||= begin @app_cache_path ||= self[:cache_path] || "vendor/cache"
path = self[:cache_path] || "vendor/cache"
raise InvalidOption, "Cache path must be relative to the bundle path" if path.start_with?("/")
path
end
end end
private def validate!
all.each do |raw_key|
[@local_config, ENV, @global_config].each do |settings|
value = converted_value(settings[key_for(raw_key)], raw_key)
Validator.validate!(raw_key, value, settings.to_hash.dup)
end
end
end
def key_for(key) def key_for(key)
key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key
@ -220,15 +288,17 @@ module Bundler
"BUNDLE_#{key}" "BUNDLE_#{key}"
end end
private
def parent_setting_for(name) def parent_setting_for(name)
split_specfic_setting_for(name)[0] split_specific_setting_for(name)[0]
end end
def specfic_gem_for(name) def specific_gem_for(name)
split_specfic_setting_for(name)[1] split_specific_setting_for(name)[1]
end end
def split_specfic_setting_for(name) def split_specific_setting_for(name)
name.split(".") name.split(".")
end end
@ -245,24 +315,39 @@ module Bundler
end end
end end
def is_num(value) def is_num(key)
NUMBER_KEYS.include?(value.to_s) NUMBER_KEYS.include?(key.to_s)
end end
def get_array(key) def is_array(key)
self[key] ? self[key].split(":").map(&:to_sym) : [] ARRAY_KEYS.include?(key.to_s)
end end
def set_array(key, array) def to_array(value)
self[key] = (array.empty? ? nil : array.join(":")) if array return [] unless value
value.split(":").map(&:to_sym)
end end
def set_key(key, value, hash, file) def array_to_s(array)
key = key_for(key) array = Array(array)
return nil if array.empty?
array.join(":").tr(" ", ":")
end
def set_key(raw_key, value, hash, file)
raw_key = raw_key.to_s
value = array_to_s(value) if is_array(raw_key)
key = key_for(raw_key)
return if hash[key] == value
unless hash[key] == value
hash[key] = value hash[key] = value
hash.delete(key) if value.nil? hash.delete(key) if value.nil?
Validator.validate!(raw_key, converted_value(value, raw_key), hash)
return unless file
SharedHelpers.filesystem_access(file) do |p| SharedHelpers.filesystem_access(file) do |p|
FileUtils.mkdir_p(p.dirname) FileUtils.mkdir_p(p.dirname)
require "bundler/yaml_serializer" require "bundler/yaml_serializer"
@ -270,18 +355,17 @@ module Bundler
end end
end end
value
end
def converted_value(value, key) def converted_value(value, key)
if value.nil? if is_array(key)
to_array(value)
elsif value.nil?
nil nil
elsif is_bool(key) || value == "false" elsif is_bool(key) || value == "false"
to_bool(value) to_bool(value)
elsif is_num(key) elsif is_num(key)
value.to_i value.to_i
else else
value value.to_s
end end
end end
@ -325,16 +409,34 @@ module Bundler
end end
end end
PER_URI_OPTIONS = %w[
fallback_timeout
].freeze
NORMALIZE_URI_OPTIONS_PATTERN =
/
\A
(\w+\.)? # optional prefix key
(https?.*?) # URI
(\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key
\z
/ix
# TODO: duplicates Rubygems#normalize_uri # TODO: duplicates Rubygems#normalize_uri
# TODO: is this the correct place to validate mirror URIs? # TODO: is this the correct place to validate mirror URIs?
def self.normalize_uri(uri) def self.normalize_uri(uri)
uri = uri.to_s uri = uri.to_s
uri = "#{uri}/" unless uri =~ %r{/\Z} if uri =~ NORMALIZE_URI_OPTIONS_PATTERN
prefix = $1
uri = $2
suffix = $3
end
uri = "#{uri}/" unless uri.end_with?("/")
uri = URI(uri) uri = URI(uri)
unless uri.absolute? unless uri.absolute?
raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri)
end end
uri "#{prefix}#{uri}#{suffix}"
end end
end end
end end

View file

@ -0,0 +1,79 @@
# frozen_string_literal: true
module Bundler
class Settings
class Validator
class Rule
attr_reader :description
def initialize(keys, description, &validate)
@keys = keys
@description = description
@validate = validate
end
def validate!(key, value, settings)
instance_exec(key, value, settings, &@validate)
end
def fail!(key, value, *reasons)
reasons.unshift @description
raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}"
end
def set(settings, key, value, *reasons)
hash_key = k(key)
return if settings[hash_key] == value
reasons.unshift @description
Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}"
if value.nil?
settings.delete(hash_key)
else
settings[hash_key] = value
end
end
def k(key)
Bundler.settings.key_for(key)
end
end
def self.rules
@rules ||= Hash.new {|h, k| h[k] = [] }
end
private_class_method :rules
def self.rule(keys, description, &blk)
rule = Rule.new(keys, description, &blk)
keys.each {|k| rules[k] << rule }
end
private_class_method :rule
def self.validate!(key, value, settings)
rules_to_validate = rules[key]
rules_to_validate.each {|rule| rule.validate!(key, value, settings) }
end
rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings|
if key == "path" && value
set(settings, "path.system", nil)
elsif key == "path.system" && value
set(settings, :path, nil)
end
end
rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings|
with = settings.fetch(k(:with), "").split(":").map(&:to_sym)
without = settings.fetch(k(:without), "").split(":").map(&:to_sym)
other_key = key == "with" ? :without : :with
other_setting = key == "with" ? without : with
conflicting = with & without
if conflicting.any?
fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict")
end
end
end
end
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/shared_helpers" require "bundler/shared_helpers"
if Bundler::SharedHelpers.in_bundle? if Bundler::SharedHelpers.in_bundle?

View file

@ -1,7 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
require "bundler/compatibility_guard"
require "pathname" require "pathname"
require "rubygems" require "rubygems"
require "bundler/version"
require "bundler/constants" require "bundler/constants"
require "bundler/rubygems_integration" require "bundler/rubygems_integration"
require "bundler/current_ruby" require "bundler/current_ruby"
@ -19,10 +23,16 @@ end
module Bundler module Bundler
module SharedHelpers module SharedHelpers
def default_gemfile def root
gemfile = find_gemfile gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
Pathname.new(gemfile).untaint Pathname.new(gemfile).untaint.expand_path.parent
end
def default_gemfile
gemfile = find_gemfile(:order_matters)
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
Pathname.new(gemfile).untaint.expand_path
end end
def default_lockfile def default_lockfile
@ -63,7 +73,7 @@ module Bundler
end end
def with_clean_git_env(&block) def with_clean_git_env(&block)
keys = %w(GIT_DIR GIT_WORK_TREE) keys = %w[GIT_DIR GIT_WORK_TREE]
old_env = keys.inject({}) do |h, k| old_env = keys.inject({}) do |h, k|
h.update(k => ENV[k]) h.update(k => ENV[k])
end end
@ -129,20 +139,34 @@ module Bundler
namespace.const_get(constant_name) namespace.const_get(constant_name)
end end
def major_deprecation(message) def major_deprecation(major_version, message)
if Bundler.bundler_major_version >= major_version
require "bundler/errors"
raise DeprecatedError, "[REMOVED FROM #{major_version}.0] #{message}"
end
return unless prints_major_deprecations? return unless prints_major_deprecations?
@major_deprecation_ui ||= Bundler::UI::Shell.new("no-color" => true) @major_deprecation_ui ||= Bundler::UI::Shell.new("no-color" => true)
ui = Bundler.ui.is_a?(@major_deprecation_ui.class) ? Bundler.ui : @major_deprecation_ui ui = Bundler.ui.is_a?(@major_deprecation_ui.class) ? Bundler.ui : @major_deprecation_ui
ui.warn("[DEPRECATED FOR #{Bundler::VERSION.split(".").first.to_i + 1}.0] #{message}") ui.warn("[DEPRECATED FOR #{major_version}.0] #{message}")
end end
def print_major_deprecations! def print_major_deprecations!
deprecate_gemfile(find_gemfile) if find_gemfile == find_file("Gemfile") multiple_gemfiles = search_up(".") do |dir|
gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) }
next if gemfiles.empty?
break false if gemfiles.size == 1
end
if multiple_gemfiles && Bundler.bundler_major_version == 1
Bundler::SharedHelpers.major_deprecation 2, \
"gems.rb and gems.locked will be preferred to Gemfile and Gemfile.lock."
end
if RUBY_VERSION < "2" if RUBY_VERSION < "2"
major_deprecation("Bundler will only support ruby >= 2.0, you are running #{RUBY_VERSION}") major_deprecation(2, "Bundler will only support ruby >= 2.0, you are running #{RUBY_VERSION}")
end end
return if Bundler.rubygems.provides?(">= 2") return if Bundler.rubygems.provides?(">= 2")
major_deprecation("Bundler will only support rubygems >= 2.0, you are running #{Bundler.rubygems.version}") major_deprecation(2, "Bundler will only support rubygems >= 2.0, you are running #{Bundler.rubygems.version}")
end end
def trap(signal, override = false, &block) def trap(signal, override = false, &block)
@ -170,23 +194,59 @@ module Bundler
"\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem."
end end
def pretty_dependency(dep, print_source = false)
msg = String.new(dep.name)
msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
if dep.is_a?(Bundler::Dependency)
platform_string = dep.platforms.join(", ")
msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY
end
msg << " from the `#{dep.source}` source" if print_source && dep.source
msg
end
def md5_available?
return @md5_available if defined?(@md5_available)
@md5_available = begin
require "openssl"
OpenSSL::Digest::MD5.digest("")
true
rescue LoadError
true
rescue OpenSSL::Digest::DigestError
false
end
end
def digest(name)
require "digest"
Digest(name)
end
private private
def validate_bundle_path def validate_bundle_path
return unless Bundler.bundle_path.to_s.include?(File::PATH_SEPARATOR) path_separator = Bundler.rubygems.path_separator
message = "Your bundle path contains a '#{File::PATH_SEPARATOR}', " \ return unless Bundler.bundle_path.to_s.split(path_separator).size > 1
message = "Your bundle path contains text matching #{path_separator.inspect}, " \
"which is the path separator for your system. Bundler cannot " \ "which is the path separator for your system. Bundler cannot " \
"function correctly when the Bundle path contains the " \ "function correctly when the Bundle path contains the " \
"system's PATH separator. Please change your " \ "system's PATH separator. Please change your " \
"bundle path to not include '#{File::PATH_SEPARATOR}'." \ "bundle path to not match #{path_separator.inspect}." \
"\nYour current bundle path is '#{Bundler.bundle_path}'." "\nYour current bundle path is '#{Bundler.bundle_path}'."
raise Bundler::PathError, message raise Bundler::PathError, message
end end
def find_gemfile def find_gemfile(order_matters = false)
given = ENV["BUNDLE_GEMFILE"] given = ENV["BUNDLE_GEMFILE"]
return given if given && !given.empty? return given if given && !given.empty?
find_file("Gemfile", "gems.rb") names = gemfile_names
names.reverse! if order_matters && Bundler.feature_flag.prefer_gems_rb?
find_file(*names)
end
def gemfile_names
["Gemfile", "gems.rb"]
end end
def find_file(*names) def find_file(*names)
@ -226,40 +286,51 @@ module Bundler
end end
end end
def set_env(key, value)
raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key)
orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}"
orig = ENV[key]
orig ||= EnvironmentPreserver::INTENTIONALLY_NIL
ENV[orig_key] ||= orig
ENV[key] = value
end
public :set_env
def set_bundle_variables def set_bundle_variables
begin begin
ENV["BUNDLE_BIN_PATH"] = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", Bundler.rubygems.bin_path("bundler", "bundle", VERSION)
rescue Gem::GemNotFoundException rescue Gem::GemNotFoundException
if File.exist?(File.expand_path("../../../exe/bundle", __FILE__)) if File.exist?(File.expand_path("../../../exe/bundle", __FILE__))
ENV["BUNDLE_BIN_PATH"] = File.expand_path("../../../exe/bundle", __FILE__) Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", File.expand_path("../../../exe/bundle", __FILE__)
else else
ENV["BUNDLE_BIN_PATH"] = File.expand_path("../../../../bin/bundle", __FILE__) Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", File.expand_path("../../../../bin/bundle", __FILE__)
end end
end end
# Set BUNDLE_GEMFILE # Set BUNDLE_GEMFILE
ENV["BUNDLE_GEMFILE"] = find_gemfile.to_s Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile(:order_matters).to_s
ENV["BUNDLER_VERSION"] = Bundler::VERSION Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
end end
def set_path def set_path
validate_bundle_path validate_bundle_path
paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
paths.unshift "#{Bundler.bundle_path}/bin" paths.unshift "#{Bundler.bundle_path}/bin"
ENV["PATH"] = paths.uniq.join(File::PATH_SEPARATOR) Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR)
end end
def set_rubyopt def set_rubyopt
rubyopt = [ENV["RUBYOPT"]].compact rubyopt = [ENV["RUBYOPT"]].compact
return if !rubyopt.empty? && rubyopt.first =~ %r{-rbundler/setup} return if !rubyopt.empty? && rubyopt.first =~ %r{-rbundler/setup}
rubyopt.unshift %(-rbundler/setup) rubyopt.unshift %(-rbundler/setup)
ENV["RUBYOPT"] = rubyopt.join(" ") Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ")
end end
def set_rubylib def set_rubylib
rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR)
rubylib.unshift bundler_ruby_lib rubylib.unshift bundler_ruby_lib
ENV["RUBYLIB"] = rubylib.uniq.join(File::PATH_SEPARATOR) Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR)
end end
def bundler_ruby_lib def bundler_ruby_lib
@ -290,12 +361,6 @@ module Bundler
true true
end end
def deprecate_gemfile(gemfile)
return unless gemfile && File.basename(gemfile) == "Gemfile"
Bundler::SharedHelpers.major_deprecation \
"gems.rb and gems.locked will be preferred to Gemfile and Gemfile.lock."
end
extend self extend self
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class SimilarityDetector class SimilarityDetector
SimilarityScore = Struct.new(:string, :distance) SimilarityScore = Struct.new(:string, :distance)

View file

@ -1,8 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Source class Source
autoload :Gemspec, "bundler/source/gemspec" autoload :Gemspec, "bundler/source/gemspec"
autoload :Git, "bundler/source/git" autoload :Git, "bundler/source/git"
autoload :Metadata, "bundler/source/metadata"
autoload :Path, "bundler/source/path" autoload :Path, "bundler/source/path"
autoload :Rubygems, "bundler/source/rubygems" autoload :Rubygems, "bundler/source/rubygems"
@ -31,6 +33,15 @@ module Bundler
spec.source == self spec.source == self
end 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.
def double_check_for(*); end
def dependency_names_to_double_check
specs.dependency_names
end
def include?(other) def include?(other)
other == self other == self
end end
@ -39,6 +50,10 @@ module Bundler
"#<#{self.class}:0x#{object_id} #{self}>" "#<#{self.class}:0x#{object_id} #{self}>"
end end
def path?
instance_of?(Bundler::Source::Path)
end
private private
def version_color(spec_version, locked_spec_version) def version_color(spec_version, locked_spec_version)
@ -54,5 +69,26 @@ module Bundler
def earlier_version?(spec_version, locked_spec_version) def earlier_version?(spec_version, locked_spec_version)
Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version)
end end
def print_using_message(message)
if !message.include?("(was ") && Bundler.feature_flag.suppress_install_using_messages?
Bundler.ui.debug message
else
Bundler.ui.info message
end
end
def extension_cache_path(spec)
return unless Bundler.feature_flag.global_gem_cache?
return unless source_slug = extension_cache_slug(spec)
Bundler.user_cache.join(
"extensions", Gem::Platform.local.to_s, Bundler.ruby_scope,
source_slug, spec.full_name
)
end
def extension_cache_slug(_)
nil
end
end end
end end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Bundler module Bundler
class Source class Source
class Gemspec < Path class Gemspec < Path

Some files were not shown because too many files have changed in this diff Show more