diff options
author | hsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-22 23:08:05 +0000 |
---|---|---|
committer | hsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-22 23:08:05 +0000 |
commit | 7825e8363d4b2ccad8e2d3f5eeba9e26f6656911 (patch) | |
tree | 83cbcf419e0feeb2ab0fd063ed85e0776eb0081b | |
parent | 73bed0312895322e0fd18310e840356c8e6af812 (diff) |
Postponing the Bundler merge.
I faced a big issue about Bundler with ruby core.
I have no time to resolve it issue before 2.5 final release.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61416 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1100 files changed, 19 insertions, 71581 deletions
@@ -845,32 +845,3 @@ test/rubygems: IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -lib/bundler: -lib/bundler.rb: -lib/bundler.gemspec: -spec/bundler: - - Portions copyright (c) 2010 Andre Arko - Portions copyright (c) 2009 Engine Yard - - MIT License - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -236,12 +236,6 @@ with all sufficient information, see the ChangeLog file or Redmine * BigDecimal#dup -* Bundler - - * Add Bundler to Standard Library. [Feature #12733] - - * Use 1.16.1. It's latest stable version. - * Coverage * Support branch coverage and method coverage [Feature #13901] diff --git a/bin/bundle b/bin/bundle deleted file mode 100755 index aaf773745d..0000000000 --- a/bin/bundle +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# Exit cleanly from an early interrupt -Signal.trap("INT") do - Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) - exit 1 -end - -require "bundler" -# Check if an older version of bundler is installed -$LOAD_PATH.each do |path| - next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9 - err = String.new - err << "Looks like you have a version of bundler that's older than 0.9.\n" - err << "Please remove your old versions.\n" - err << "An easy way to do this is by running `gem cleanup bundler`." - abort(err) -end - -require "bundler/friendly_errors" -Bundler.with_friendly_errors do - require "bundler/cli" - - # Allow any command to use --help flag to show help for that command - help_flags = %w[--help -h] - help_flag_used = ARGV.any? {|a| help_flags.include? a } - args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV - - Bundler::CLI.start(args, :debug => true) -end diff --git a/bin/bundler b/bin/bundler deleted file mode 100755 index d9131fe834..0000000000 --- a/bin/bundler +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -load File.expand_path("../bundle", __FILE__) @@ -1182,21 +1182,6 @@ yes-test-bundled-gems: test-bundled-gems-run no-test-bundled-gems: test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS) -test-bundler-precheck: $(arch)-fake.rb programs - -yes-test-bundler-prepare: test-bundler-precheck - $(XRUBY) -C "$(srcdir)" bin/gem install --no-ri --no-rdoc \ - --install-dir .bundle --conservative "rspec:~> 3.5" - -RSPECOPTS = --format progress -BUNDLER_SPECS = -test-bundler: $(TEST_RUNNABLE)-test-bundler -yes-test-bundler: yes-test-bundler-prepare - $(gnumake_recursive)$(Q) \ - $(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec \ - --require spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS) -no-test-bundler: - UNICODE_FILES = $(UNICODE_SRC_DATA_DIR)/UnicodeData.txt \ $(UNICODE_SRC_DATA_DIR)/CompositionExclusions.txt \ $(UNICODE_SRC_DATA_DIR)/NormalizationTest.txt \ @@ -1368,7 +1353,6 @@ help: PHONY " test-all: all ruby tests [TESTOPTS=-j4 TESTS=<test files>]" \ " test-spec: run the Ruby spec suite" \ " test-rubyspec: same as test-spec" \ - " test-bundler: run the Bundler spec" \ " test-bundled-gems: run the test suite of bundled gems" \ " up: update local copy and autogenerated files" \ " benchmark: benchmark this ruby and COMPARE_RUBY." \ diff --git a/defs/gmake.mk b/defs/gmake.mk index 5305790e6f..d961e27f77 100644 --- a/defs/gmake.mk +++ b/defs/gmake.mk @@ -61,7 +61,7 @@ endif ORDERED_TEST_TARGETS := $(filter $(TEST_TARGETS), \ btest-ruby test-knownbug test-basic \ test-testframework test-ruby test-almost test-all \ - test-spec test-bundler-prepare test-bundler \ + test-spec \ ) prev_test := $(if $(filter test-spec,$(ORDERED_TEST_TARGETS)),test-spec-precheck) $(foreach test,$(ORDERED_TEST_TARGETS), \ diff --git a/doc/maintainers.rdoc b/doc/maintainers.rdoc index 0cae82c419..382a4e2cbf 100644 --- a/doc/maintainers.rdoc +++ b/doc/maintainers.rdoc @@ -208,9 +208,6 @@ Zachary Scott (zzak) === Libraries -[lib/bundler.rb, lib/bundler/*] - Hiroshi SHIBATA (hsbt) - https://github.com/bundler/bundler [lib/cmath.rb] _unmaintained_ https://github.com/ruby/cmath diff --git a/lib/bundler.gemspec b/lib/bundler.gemspec deleted file mode 100644 index 227191b090..0000000000 --- a/lib/bundler.gemspec +++ /dev/null @@ -1,347 +0,0 @@ -# coding: utf-8 -# frozen_string_literal: true - -begin - require File.expand_path("../lib/bundler/version", __FILE__) -rescue LoadError # for Ruby core repository - require File.expand_path("../bundler/version", __FILE__) -end -require "shellwords" - -Gem::Specification.new do |s| - s.name = "bundler" - s.version = Bundler::VERSION - s.license = "MIT" - s.authors = [ - "André Arko", "Samuel Giddins", "Chris Morris", "James Wen", "Tim Moore", - "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", - "Yehuda Katz" - ] - s.email = ["team@bundler.io"] - s.homepage = "http://bundler.io" - s.summary = "The best way to manage your application's dependencies" - s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably" - - if s.respond_to?(:metadata=) - s.metadata = { - "bug_tracker_uri" => "http://github.com/bundler/bundler/issues", - "changelog_uri" => "https://github.com/bundler/bundler/blob/master/CHANGELOG.md", - "homepage_uri" => "https://bundler.io/", - "source_code_uri" => "http://github.com/bundler/bundler/", - } - 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_rubygems_version = ">= 1.3.6" - end - - s.add_development_dependency "automatiek", "~> 0.1.0" - s.add_development_dependency "mustache", "0.99.6" - s.add_development_dependency "rake", "~> 10.0" - s.add_development_dependency "rdiscount", "~> 2.2" - s.add_development_dependency "ronn", "~> 0.7.3" - s.add_development_dependency "rspec", "~> 3.6" - - s.files = %w[ - exe/bundle - exe/bundle_ruby - exe/bundler - lib/bundler.rb - lib/bundler/build_metadata.rb - lib/bundler/capistrano.rb - lib/bundler/cli.rb - lib/bundler/cli/add.rb - lib/bundler/cli/binstubs.rb - lib/bundler/cli/cache.rb - lib/bundler/cli/check.rb - lib/bundler/cli/clean.rb - lib/bundler/cli/common.rb - lib/bundler/cli/config.rb - lib/bundler/cli/console.rb - lib/bundler/cli/doctor.rb - lib/bundler/cli/exec.rb - lib/bundler/cli/gem.rb - lib/bundler/cli/info.rb - lib/bundler/cli/init.rb - lib/bundler/cli/inject.rb - lib/bundler/cli/install.rb - lib/bundler/cli/issue.rb - lib/bundler/cli/list.rb - lib/bundler/cli/lock.rb - lib/bundler/cli/open.rb - lib/bundler/cli/outdated.rb - lib/bundler/cli/package.rb - lib/bundler/cli/platform.rb - lib/bundler/cli/plugin.rb - lib/bundler/cli/pristine.rb - lib/bundler/cli/show.rb - lib/bundler/cli/update.rb - lib/bundler/cli/viz.rb - lib/bundler/compact_index_client.rb - lib/bundler/compact_index_client/cache.rb - lib/bundler/compact_index_client/updater.rb - lib/bundler/compatibility_guard.rb - lib/bundler/constants.rb - lib/bundler/current_ruby.rb - lib/bundler/definition.rb - lib/bundler/dep_proxy.rb - lib/bundler/dependency.rb - lib/bundler/deployment.rb - lib/bundler/deprecate.rb - lib/bundler/dsl.rb - lib/bundler/endpoint_specification.rb - lib/bundler/env.rb - lib/bundler/environment_preserver.rb - lib/bundler/errors.rb - lib/bundler/feature_flag.rb - lib/bundler/fetcher.rb - lib/bundler/fetcher/base.rb - lib/bundler/fetcher/compact_index.rb - lib/bundler/fetcher/dependency.rb - lib/bundler/fetcher/downloader.rb - lib/bundler/fetcher/index.rb - lib/bundler/friendly_errors.rb - lib/bundler/gem_helper.rb - lib/bundler/gem_helpers.rb - lib/bundler/gem_remote_fetcher.rb - lib/bundler/gem_tasks.rb - lib/bundler/gem_version_promoter.rb - lib/bundler/gemdeps.rb - lib/bundler/graph.rb - lib/bundler/index.rb - lib/bundler/injector.rb - lib/bundler/inline.rb - lib/bundler/installer.rb - lib/bundler/installer/gem_installer.rb - lib/bundler/installer/parallel_installer.rb - lib/bundler/installer/standalone.rb - lib/bundler/lazy_specification.rb - lib/bundler/lockfile_generator.rb - lib/bundler/lockfile_parser.rb - lib/bundler/match_platform.rb - lib/bundler/mirror.rb - lib/bundler/plugin.rb - lib/bundler/plugin/api.rb - lib/bundler/plugin/api/source.rb - lib/bundler/plugin/dsl.rb - lib/bundler/plugin/index.rb - lib/bundler/plugin/installer.rb - lib/bundler/plugin/installer/git.rb - lib/bundler/plugin/installer/rubygems.rb - lib/bundler/plugin/source_list.rb - lib/bundler/process_lock.rb - lib/bundler/psyched_yaml.rb - lib/bundler/remote_specification.rb - lib/bundler/resolver.rb - lib/bundler/resolver/spec_group.rb - lib/bundler/retry.rb - lib/bundler/ruby_dsl.rb - lib/bundler/ruby_version.rb - lib/bundler/rubygems_ext.rb - lib/bundler/rubygems_gem_installer.rb - lib/bundler/rubygems_integration.rb - lib/bundler/runtime.rb - lib/bundler/settings.rb - lib/bundler/settings/validator.rb - lib/bundler/setup.rb - lib/bundler/shared_helpers.rb - lib/bundler/similarity_detector.rb - lib/bundler/source.rb - lib/bundler/source/gemspec.rb - lib/bundler/source/git.rb - lib/bundler/source/git/git_proxy.rb - lib/bundler/source/metadata.rb - lib/bundler/source/path.rb - lib/bundler/source/path/installer.rb - lib/bundler/source/rubygems.rb - lib/bundler/source/rubygems/remote.rb - lib/bundler/source_list.rb - lib/bundler/spec_set.rb - lib/bundler/ssl_certs/.document - lib/bundler/ssl_certs/certificate_manager.rb - lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem - lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem - lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem - lib/bundler/stub_specification.rb - lib/bundler/templates/.document - lib/bundler/templates/Executable - lib/bundler/templates/Executable.bundler - lib/bundler/templates/Executable.standalone - lib/bundler/templates/Gemfile - lib/bundler/templates/gems.rb - lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt - lib/bundler/templates/newgem/Gemfile.tt - lib/bundler/templates/newgem/LICENSE.txt.tt - lib/bundler/templates/newgem/README.md.tt - lib/bundler/templates/newgem/Rakefile.tt - lib/bundler/templates/newgem/bin/console.tt - lib/bundler/templates/newgem/bin/setup.tt - lib/bundler/templates/newgem/exe/newgem.tt - lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt - lib/bundler/templates/newgem/ext/newgem/newgem.c.tt - lib/bundler/templates/newgem/ext/newgem/newgem.h.tt - lib/bundler/templates/newgem/gitignore.tt - lib/bundler/templates/newgem/lib/newgem.rb.tt - lib/bundler/templates/newgem/lib/newgem/version.rb.tt - lib/bundler/templates/newgem/newgem.gemspec.tt - lib/bundler/templates/newgem/rspec.tt - lib/bundler/templates/newgem/spec/newgem_spec.rb.tt - lib/bundler/templates/newgem/spec/spec_helper.rb.tt - lib/bundler/templates/newgem/test/newgem_test.rb.tt - lib/bundler/templates/newgem/test/test_helper.rb.tt - lib/bundler/templates/newgem/travis.yml.tt - lib/bundler/ui.rb - lib/bundler/ui/rg_proxy.rb - lib/bundler/ui/shell.rb - lib/bundler/ui/silent.rb - lib/bundler/uri_credentials_filter.rb - lib/bundler/vendor/fileutils/lib/fileutils.rb - lib/bundler/vendor/molinillo/lib/molinillo.rb - lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb - lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb - lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb - lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb - lib/bundler/vendor/molinillo/lib/molinillo/errors.rb - lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb - lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb - lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb - lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb - lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb - lib/bundler/vendor/molinillo/lib/molinillo/state.rb - lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb - lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb - lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb - lib/bundler/vendor/thor/lib/thor.rb - lib/bundler/vendor/thor/lib/thor/actions.rb - lib/bundler/vendor/thor/lib/thor/actions/create_file.rb - lib/bundler/vendor/thor/lib/thor/actions/create_link.rb - lib/bundler/vendor/thor/lib/thor/actions/directory.rb - lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb - lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb - lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb - lib/bundler/vendor/thor/lib/thor/base.rb - lib/bundler/vendor/thor/lib/thor/command.rb - lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb - lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb - lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb - lib/bundler/vendor/thor/lib/thor/error.rb - lib/bundler/vendor/thor/lib/thor/group.rb - lib/bundler/vendor/thor/lib/thor/invocation.rb - lib/bundler/vendor/thor/lib/thor/line_editor.rb - lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb - lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb - lib/bundler/vendor/thor/lib/thor/parser.rb - lib/bundler/vendor/thor/lib/thor/parser/argument.rb - lib/bundler/vendor/thor/lib/thor/parser/arguments.rb - lib/bundler/vendor/thor/lib/thor/parser/option.rb - lib/bundler/vendor/thor/lib/thor/parser/options.rb - lib/bundler/vendor/thor/lib/thor/rake_compat.rb - lib/bundler/vendor/thor/lib/thor/runner.rb - lib/bundler/vendor/thor/lib/thor/shell.rb - lib/bundler/vendor/thor/lib/thor/shell/basic.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 - bundler.gemspec - ] - - s.bindir = "exe" - s.executables = %w[bundle bundler] - s.require_paths = ["lib"] -end diff --git a/lib/bundler.rb b/lib/bundler.rb deleted file mode 100644 index bef2caabcf..0000000000 --- a/lib/bundler.rb +++ /dev/null @@ -1,545 +0,0 @@ -# frozen_string_literal: true - -require "bundler/compatibility_guard" - -require "bundler/vendored_fileutils" -require "pathname" -require "rbconfig" -require "thread" - -require "bundler/errors" -require "bundler/environment_preserver" -require "bundler/plugin" -require "bundler/rubygems_ext" -require "bundler/rubygems_integration" -require "bundler/version" -require "bundler/constants" -require "bundler/current_ruby" -require "bundler/build_metadata" - -module Bundler - environment_preserver = EnvironmentPreserver.new(ENV, EnvironmentPreserver::BUNDLER_KEYS) - ORIGINAL_ENV = environment_preserver.restore - ENV.replace(environment_preserver.backup) - SUDO_MUTEX = Mutex.new - - autoload :Definition, "bundler/definition" - autoload :Dependency, "bundler/dependency" - autoload :DepProxy, "bundler/dep_proxy" - autoload :Deprecate, "bundler/deprecate" - autoload :Dsl, "bundler/dsl" - autoload :EndpointSpecification, "bundler/endpoint_specification" - autoload :Env, "bundler/env" - autoload :Fetcher, "bundler/fetcher" - autoload :FeatureFlag, "bundler/feature_flag" - autoload :GemHelper, "bundler/gem_helper" - autoload :GemHelpers, "bundler/gem_helpers" - autoload :GemRemoteFetcher, "bundler/gem_remote_fetcher" - autoload :GemVersionPromoter, "bundler/gem_version_promoter" - autoload :Graph, "bundler/graph" - autoload :Index, "bundler/index" - autoload :Injector, "bundler/injector" - autoload :Installer, "bundler/installer" - autoload :LazySpecification, "bundler/lazy_specification" - autoload :LockfileParser, "bundler/lockfile_parser" - autoload :MatchPlatform, "bundler/match_platform" - autoload :ProcessLock, "bundler/process_lock" - autoload :RemoteSpecification, "bundler/remote_specification" - autoload :Resolver, "bundler/resolver" - autoload :Retry, "bundler/retry" - autoload :RubyDsl, "bundler/ruby_dsl" - autoload :RubyGemsGemInstaller, "bundler/rubygems_gem_installer" - autoload :RubyVersion, "bundler/ruby_version" - autoload :Runtime, "bundler/runtime" - autoload :Settings, "bundler/settings" - autoload :SharedHelpers, "bundler/shared_helpers" - autoload :Source, "bundler/source" - autoload :SourceList, "bundler/source_list" - autoload :SpecSet, "bundler/spec_set" - autoload :StubSpecification, "bundler/stub_specification" - autoload :UI, "bundler/ui" - autoload :URICredentialsFilter, "bundler/uri_credentials_filter" - autoload :VersionRanges, "bundler/version_ranges" - - class << self - def configure - @configured ||= configure_gem_home_and_path - end - - def ui - (defined?(@ui) && @ui) || (self.ui = UI::Silent.new) - end - - def ui=(ui) - Bundler.rubygems.ui = ui ? UI::RGProxy.new(ui) : nil - @ui = ui - end - - # Returns absolute path of where gems are installed on the filesystem. - def bundle_path - @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) - end - - def configured_bundle_path - @configured_bundle_path ||= settings.path.tap(&:validate!) - end - - # Returns absolute location of where binstubs are installed to. - def bin_path - @bin_path ||= begin - path = settings[:bin] || "bin" - path = Pathname.new(path).expand_path(root).expand_path - SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) } - path - end - end - - def setup(*groups) - # Return if all groups are already loaded - return @setup if defined?(@setup) && @setup - - definition.validate_runtime! - - SharedHelpers.print_major_deprecations! - - if groups.empty? - # Load all groups, but only once - @setup = load.setup - else - load.setup(*groups) - end - end - - def require(*groups) - setup(*groups).require(*groups) - end - - def load - @load ||= Runtime.new(root, definition) - end - - def environment - SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load" - load - end - - # Returns an instance of Bundler::Definition for given Gemfile and lockfile - # - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @return [Bundler::Definition] - def definition(unlock = nil) - @definition = nil if unlock - @definition ||= begin - configure - Definition.build(default_gemfile, default_lockfile, unlock) - end - end - - def frozen? - frozen = settings[:deployment] - frozen ||= settings[:frozen] unless feature_flag.deployment_means_frozen? - frozen - end - - def locked_gems - @locked_gems ||= - if defined?(@definition) && @definition - definition.locked_gems - elsif Bundler.default_lockfile.file? - lock = Bundler.read_file(Bundler.default_lockfile) - LockfileParser.new(lock) - end - end - - def ruby_scope - "#{Bundler.rubygems.ruby_engine}/#{Bundler.rubygems.config_map[:ruby_version]}" - end - - def user_home - @user_home ||= begin - home = Bundler.rubygems.user_home - - warning = if home.nil? - "Your home directory is not set." - elsif !File.directory?(home) - "`#{home}` is not a directory." - elsif !File.writable?(home) - "`#{home}` is not writable." - end - - if warning - user_home = tmp_home_path(Etc.getlogin, warning) - Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n" - user_home - else - Pathname.new(home) - end - end - end - - def tmp_home_path(login, warning) - login ||= "unknown" - Kernel.send(:require, "tmpdir") - path = Pathname.new(Dir.tmpdir).join("bundler", "home") - SharedHelpers.filesystem_access(path) do |tmp_home_path| - unless tmp_home_path.exist? - tmp_home_path.mkpath - tmp_home_path.chmod(0o777) - end - tmp_home_path.join(login).tap(&:mkpath) - end - rescue => e - raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}") - end - - def user_bundle_path - Pathname.new(user_home).join(".bundle") - end - - def home - bundle_path.join("bundler") - end - - def install_path - home.join("gems") - end - - def specs_path - bundle_path.join("specifications") - end - - def user_cache - user_bundle_path.join("cache") - end - - def root - @root ||= begin - SharedHelpers.root - rescue GemfileNotFound - bundle_dir = default_bundle_dir - raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir - Pathname.new(File.expand_path("..", bundle_dir)) - end - end - - def app_config_path - if app_config = ENV["BUNDLE_APP_CONFIG"] - Pathname.new(app_config).expand_path(root) - else - root.join(".bundle") - end - end - - def app_cache(custom_path = nil) - path = custom_path || root - Pathname.new(path).join(settings.app_cache_path) - end - - def tmp(name = Process.pid.to_s) - Kernel.send(:require, "tmpdir") - Pathname.new(Dir.mktmpdir(["bundler", name])) - end - - def rm_rf(path) - FileUtils.remove_entry_secure(path) if path && File.exist?(path) - rescue ArgumentError - message = <<EOF -It is a security vulnerability to allow your home directory to be world-writable, and bundler can not continue. -You should probably consider fixing this issue by running `chmod o-w ~` on *nix. -Please refer to http://ruby-doc.org/stdlib-2.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details. -EOF - File.world_writable?(path) ? Bundler.ui.warn(message) : raise - raise PathError, "Please fix the world-writable issue with your #{path} directory" - end - - def settings - @settings ||= Settings.new(app_config_path) - rescue GemfileNotFound - @settings = Settings.new(Pathname.new(".bundle").expand_path) - end - - # @return [Hash] Environment present before Bundler was activated - def original_env - ORIGINAL_ENV.clone - end - - # @deprecated Use `original_env` instead - # @return [Hash] Environment with all bundler-related variables removed - def clean_env - Bundler::SharedHelpers.major_deprecation(2, "`Bundler.clean_env` has weird edge cases, use `.original_env` instead") - env = original_env - - if env.key?("BUNDLER_ORIG_MANPATH") - env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"] - end - - env.delete_if {|k, _| k[0, 7] == "BUNDLE_" } - - if env.key?("RUBYOPT") - env["RUBYOPT"] = env["RUBYOPT"].sub "-rbundler/setup", "" - end - - if env.key?("RUBYLIB") - rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR) - rubylib.delete(File.expand_path("..", __FILE__)) - env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR) - end - - env - end - - def with_original_env - with_env(original_env) { yield } - end - - def with_clean_env - with_env(clean_env) { yield } - end - - def clean_system(*args) - with_clean_env { Kernel.system(*args) } - end - - def clean_exec(*args) - with_clean_env { Kernel.exec(*args) } - end - - def local_platform - return Gem::Platform::RUBY if settings[:force_ruby_platform] - Gem::Platform.local - end - - def default_gemfile - SharedHelpers.default_gemfile - end - - def default_lockfile - SharedHelpers.default_lockfile - end - - def default_bundle_dir - SharedHelpers.default_bundle_dir - end - - def system_bindir - # Gem.bindir doesn't always return the location that RubyGems will install - # system binaries. If you put '-n foo' in your .gemrc, RubyGems will - # install binstubs there instead. Unfortunately, RubyGems doesn't expose - # that directory at all, so rather than parse .gemrc ourselves, we allow - # the directory to be set as well, via `bundle config bindir foo`. - Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir - end - - def use_system_gems? - configured_bundle_path.use_system_gems? - end - - def requires_sudo? - return @requires_sudo if defined?(@requires_sudo_ran) - - sudo_present = which "sudo" if settings.allow_sudo? - - if sudo_present - # the bundle path and subdirectories need to be writable for RubyGems - # to be able to unpack and install gems without exploding - path = bundle_path - path = path.parent until path.exist? - - # bins are written to a different location on OS X - bin_dir = Pathname.new(Bundler.system_bindir) - bin_dir = bin_dir.parent until bin_dir.exist? - - # if any directory is not writable, we need sudo - files = [path, bin_dir] | Dir[path.join("build_info/*").to_s] | Dir[path.join("*").to_s] - sudo_needed = files.any? {|f| !File.writable?(f) } - end - - @requires_sudo_ran = true - @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed - end - - def mkdir_p(path) - if requires_sudo? - sudo "mkdir -p '#{path}'" unless File.exist?(path) - else - SharedHelpers.filesystem_access(path, :write) do |p| - FileUtils.mkdir_p(p) - end - end - end - - def which(executable) - if File.file?(executable) && File.executable?(executable) - executable - elsif paths = ENV["PATH"] - quote = '"'.freeze - paths.split(File::PATH_SEPARATOR).find do |path| - path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) - executable_path = File.expand_path(executable, path) - return executable_path if File.file?(executable_path) && File.executable?(executable_path) - end - end - end - - def sudo(str) - SUDO_MUTEX.synchronize do - prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " " - Your user account isn't allowed to install to the system RubyGems. - You can cancel this installation and run: - - bundle install --path vendor/bundle - - to install the gems into ./vendor/bundle/, or you can enter your password - and install the bundled gems to RubyGems using sudo. - - Password: - PROMPT - - unless @prompted_for_sudo ||= system(%(sudo -k -p "#{prompt}" true)) - raise SudoNotPermittedError, - "Bundler requires sudo access to install at the moment. " \ - "Try installing again, granting Bundler sudo access when prompted, or installing into a different path." - end - - `sudo -p "#{prompt}" #{str}` - end - end - - def read_file(file) - File.open(file, "rb", &:read) - end - - def load_marshal(data) - Marshal.load(data) - rescue => e - raise MarshalError, "#{e.class}: #{e.message}" - end - - def load_gemspec(file, validate = false) - @gemspec_cache ||= {} - key = File.expand_path(file) - @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) - # Protect against caching side-effected gemspecs by returning a - # new instance each time. - @gemspec_cache[key].dup if @gemspec_cache[key] - end - - def load_gemspec_uncached(file, validate = false) - path = Pathname.new(file) - contents = path.read - spec = if contents.start_with?("---") # YAML header - eval_yaml_gemspec(path, contents) - else - # Eval the gemspec from its parent directory, because some gemspecs - # depend on "./" relative paths. - SharedHelpers.chdir(path.dirname.to_s) do - eval_gemspec(path, contents) - end - end - return unless spec - spec.loaded_from = path.expand_path.to_s - Bundler.rubygems.validate(spec) if validate - spec - end - - def clear_gemspec_cache - @gemspec_cache = {} - end - - def git_present? - return @git_present if defined?(@git_present) - @git_present = Bundler.which("git") || Bundler.which("git.exe") - end - - def feature_flag - @feature_flag ||= FeatureFlag.new(VERSION) - end - - def reset! - reset_paths! - Plugin.reset! - reset_rubygems! - end - - def reset_paths! - @bin_path = nil - @bundler_major_version = nil - @bundle_path = nil - @configured = nil - @configured_bundle_path = nil - @definition = nil - @load = nil - @locked_gems = nil - @root = nil - @settings = nil - @setup = nil - @user_home = nil - end - - def reset_rubygems! - return unless defined?(@rubygems) && @rubygems - rubygems.undo_replacements - rubygems.reset - @rubygems = nil - end - - private - - def eval_yaml_gemspec(path, contents) - Kernel.send(:require, "bundler/psyched_yaml") - - # If the YAML is invalid, Syck raises an ArgumentError, and Psych - # raises a Psych::SyntaxError. See psyched_yaml.rb for more info. - Gem::Specification.from_yaml(contents) - rescue YamlLibrarySyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception - eval_gemspec(path, contents) - end - - def eval_gemspec(path, contents) - eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s) - rescue ScriptError, StandardError => e - msg = "There was an error while loading `#{path.basename}`: #{e.message}" - - if e.is_a?(LoadError) && RUBY_VERSION >= "1.9" - msg += "\nDoes it try to require a relative path? That's been removed in Ruby 1.9" - end - - raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents) - end - - def configure_gem_home_and_path - configure_gem_path - configure_gem_home - bundle_path - end - - def configure_gem_path(env = ENV) - blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty? - if !use_system_gems? - # this needs to be empty string to cause - # PathSupport.split_gem_path to only load up the - # Bundler --path setting as the GEM_PATH. - env["GEM_PATH"] = "" - elsif blank_home - possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path] - paths = possibles.flatten.compact.uniq.reject(&:empty?) - env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR) - end - end - - def configure_gem_home - Bundler::SharedHelpers.set_env "GEM_HOME", File.expand_path(bundle_path, root) - Bundler.rubygems.clear_paths - end - - # @param env [Hash] - def with_env(env) - backup = ENV.to_hash - ENV.replace(env) - yield - ensure - ENV.replace(backup) - end - end -end diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb deleted file mode 100644 index 54436f982d..0000000000 --- a/lib/bundler/build_metadata.rb +++ /dev/null @@ -1,36 +0,0 @@ -# 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 diff --git a/lib/bundler/capistrano.rb b/lib/bundler/capistrano.rb deleted file mode 100644 index 1b7145b72b..0000000000 --- a/lib/bundler/capistrano.rb +++ /dev/null @@ -1,22 +0,0 @@ -# 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. -# -# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and -# Bundler will be activated after each new deployment. -require "bundler/deployment" -require "capistrano/version" - -if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") - raise "For Capistrano 3.x integration, please use http://github.com/capistrano/bundler" -end - -Capistrano::Configuration.instance(:must_exist).load do - before "deploy:finalize_update", "bundle:install" - Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) - set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } -end diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb deleted file mode 100644 index 05e1851c18..0000000000 --- a/lib/bundler/cli.rb +++ /dev/null @@ -1,746 +0,0 @@ -# frozen_string_literal: true - -require "bundler" -require "bundler/vendored_thor" - -module Bundler - class CLI < Thor - require "bundler/cli/common" - - 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 - ].freeze - - def self.start(*) - super - rescue Exception => e - Bundler.ui = UI::Shell.new - raise e - ensure - Bundler::SharedHelpers.print_major_deprecations! - end - - def self.dispatch(*) - super do |i| - i.send(:print_command) - i.send(:warn_on_outdated_bundler) - end - end - - def initialize(*args) - super - - custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] - if custom_gemfile && !custom_gemfile.empty? - Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) - Bundler.reset_paths! - end - - Bundler.settings.set_command_option_if_given :retry, options[:retry] - - current_cmd = args.last[:current_command].name - auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) - rescue UnknownArgumentError => e - raise InvalidOption, e.message - ensure - self.options ||= {} - unprinted_warnings = Bundler.ui.unprinted_warnings - Bundler.ui = UI::Shell.new(options) - Bundler.ui.level = "debug" if options["verbose"] - unprinted_warnings.each {|w| Bundler.ui.warn(w) } - - if ENV["RUBYGEMS_GEMDEPS"] && !ENV["RUBYGEMS_GEMDEPS"].empty? - Bundler.ui.warn( - "The RUBYGEMS_GEMDEPS environment variable is set. This enables RubyGems' " \ - "experimental Gemfile mode, which may conflict with Bundler and cause unexpected errors. " \ - "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true - ) - 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]) - stop_on_unknown_option! :exec - - 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 "retry", :type => :numeric, :aliases => "-r", :banner => "NUM", - :desc => "Specify the number of times you wish to attempt network commands" - class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V" - - def help(cli = nil) - case cli - when "gemfile" then command = "gemfile" - when nil then command = "bundle" - else command = "bundle-#{cli}" - end - - man_path = File.expand_path("../../../man", __FILE__) - man_pages = Hash[Dir.glob(File.join(man_path, "*")).grep(/.*\.\d*\Z/).collect do |f| - [File.basename(f, ".*"), f] - end] - - if man_pages.include?(command) - if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} - Kernel.exec "man #{man_pages[command]}" - else - puts File.read("#{man_path}/#{File.basename(man_pages[command])}.txt") - end - elsif command_path = Bundler.which("bundler-#{cli}") - Kernel.exec(command_path, "--help") - else - super - end - end - - def self.handle_no_command_error(command, has_namespace = $thor_runner) - if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command) - return Bundler::Plugin.exec_command(command, ARGV[1..-1]) - end - - return super unless command_path = Bundler.which("bundler-#{command}") - - Kernel.exec(command_path, *ARGV[1..-1]) - end - - desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" - long_desc <<-D - Init generates a default Gemfile in the current working directory. When adding a - 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. - D - deprecated_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" - def init - require "bundler/cli/init" - Init.new(options.dup).run - end - - desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" - long_desc <<-D - Check searches the local machine for each of the gems requested in the Gemfile. If - all gems are found, Bundler prints a success message and exits with a status of 0. - If not, the first missing gem is listed and Bundler exits status 1. - D - method_option "dry-run", :type => :boolean, :default => false, :banner => - "Lock the Gemfile" - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - 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" unless Bundler.feature_flag.forget_cli_options?}" - map "c" => "check" - def check - require "bundler/cli/check" - Check.new(options).run - end - - desc "install [OPTIONS]", "Install the current environment to the system" - long_desc <<-D - Install will install all of the gems in the current bundle, making them available - for use. In a freshly checked out repository, this command will give you the same - gem versions as the last person who updated the Gemfile and ran `bundle update`. - - Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed - into the [DIR] directory rather than into system gems. - - If the bundle has already been installed, bundler will tell you so and then exit. - D - deprecated_option "binstubs", :type => :string, :lazy_default => "bin", :banner => - "Generate bin stubs for bundled gems to ./bin" - deprecated_option "clean", :type => :boolean, :banner => - "Run bundle clean automatically after install" - deprecated_option "deployment", :type => :boolean, :banner => - "Install using defaults tuned for deployment environments" - deprecated_option "frozen", :type => :boolean, :banner => - "Do not allow the Gemfile.lock to be updated after this install" - method_option "full-index", :type => :boolean, :banner => - "Fall back to using the single-file index of all gems" - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "jobs", :aliases => "-j", :type => :numeric, :banner => - "Specify the number of jobs to run in parallel" - method_option "local", :type => :boolean, :banner => - "Do not attempt to fetch gems remotely and use the gem cache instead" - deprecated_option "no-cache", :type => :boolean, :banner => - "Don't update the existing gem cache." - method_option "redownload", :type => :boolean, :aliases => - [Bundler.feature_flag.forget_cli_options? ? nil : "--force"].compact, :banner => - "Force downloading every gem." - deprecated_option "no-prune", :type => :boolean, :banner => - "Don't remove stale gems from the cache." - 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" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - deprecated_option "shebang", :type => :string, :banner => - "Specify a different shebang executable name than the default (usually 'ruby')" - method_option "standalone", :type => :array, :lazy_default => [], :banner => - "Make a bundle that can work without the Bundler runtime" - 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" - method_option "trust-policy", :alias => "P", :type => :string, :banner => - "Gem trust policy (like gem install -P). Must be one of " + - Bundler.rubygems.security_policy_keys.join("|") - deprecated_option "without", :type => :array, :banner => - "Exclude gems that are part of the specified named group." - deprecated_option "with", :type => :array, :banner => - "Include gems that are part of the specified named group." - map "i" => "install" - def install - require "bundler/cli/install" - Bundler.settings.temporary(:no_install => false) do - Install.new(options.dup).run - end - end - - desc "update [OPTIONS]", "Update the current environment" - long_desc <<-D - 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 - possible versions of the gems in the bundle. - D - method_option "full-index", :type => :boolean, :banner => - "Fall back to using the single-file index of all gems" - method_option "group", :aliases => "-g", :type => :array, :banner => - "Update a specific group" - method_option "jobs", :aliases => "-j", :type => :numeric, :banner => - "Specify the number of jobs to run in parallel" - method_option "local", :type => :boolean, :banner => - "Do not attempt to fetch gems remotely and use the gem cache instead" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - method_option "source", :type => :array, :banner => - "Update a specific source (and all gems associated with it)" - method_option "force", :type => :boolean, :banner => - "Force downloading every gem." - method_option "ruby", :type => :boolean, :banner => - "Update ruby specified in Gemfile.lock" - method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner => - "Update the locked version of bundler" - method_option "patch", :type => :boolean, :banner => - "Prefer updating only to next patch version" - method_option "minor", :type => :boolean, :banner => - "Prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => - "Prefer updating to next major version (default)" - method_option "strict", :type => :boolean, :banner => - "Do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "conservative", :type => :boolean, :banner => - "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) - require "bundler/cli/update" - Update.new(options, gems).run - end - - desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" - long_desc <<-D - Show lists the names and versions of all gems that are required by your Gemfile. - Calling show with [GEM] will list the exact location of that gem on your machine. - D - method_option "paths", :type => :boolean, - :banner => "List the paths of all gems that are required by your Gemfile." - method_option "outdated", :type => :boolean, - :banner => "Show verbose output including whether gems are outdated." - def show(gem_name = nil) - Bundler::SharedHelpers.major_deprecation(2, "use `bundle list` instead of `bundle show`") if ARGV[0] == "show" - require "bundler/cli/show" - Show.new(options, gem_name).run - end - # TODO: 2.0 remove `bundle 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" - method_option "path", :type => :boolean, :banner => "Print full path to gem" - def info(gem_name) - require "bundler/cli/info" - Info.new(options, gem_name).run - end - - desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" - long_desc <<-D - Generate binstubs for executables in [GEM]. Binstubs are put into bin, - or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] - will create binstubs for all given gems. - D - method_option "force", :type => :boolean, :default => false, :banner => - "Overwrite existing binstubs if they exist" - method_option "path", :type => :string, :lazy_default => "bin", :banner => - "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 => - "Make binstubs that can work without the Bundler runtime" - def binstubs(*gems) - require "bundler/cli/binstubs" - Binstubs.new(options, gems).run - end - - desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" - long_desc <<-D - Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. - D - method_option "version", :aliases => "-v", :type => :string - method_option "group", :aliases => "-g", :type => :string - method_option "source", :aliases => "-s", :type => :string - - def add(gem_name) - require "bundler/cli/add" - Add.new(options.dup, gem_name).run - end - - desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" - long_desc <<-D - 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 - versions of the given gems. Prerelease gems are ignored by default. If your gems - are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. - - For more information on patch level options (--major, --minor, --patch, - --update-strict) see documentation on the same options on the update command. - D - method_option "group", :type => :string, :banner => "List gems from a specific group" - method_option "groups", :type => :boolean, :banner => "List gems organized by groups" - method_option "local", :type => :boolean, :banner => - "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 "source", :type => :array, :banner => "Check against a specific source" - method_option "strict", :type => :boolean, :banner => - "Only list newer versions allowed by your Gemfile requirements" - method_option "update-strict", :type => :boolean, :banner => - "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" - method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" - method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions" - method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions" - method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions" - method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner => - "Use minimal formatting for more parseable output" - def outdated(*gems) - require "bundler/cli/outdated" - Outdated.new(options, gems).run - 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 - 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 "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." - def cache - require "bundler/cli/cache" - Cache.new(options).run - end - end - - desc "#{Bundler.feature_flag.cache_command_is_package? ? :cache : :package} [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" - 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 "cache-path", :type => :string, :banner => - "Specify a different cache path than the default (vendor/cache)." - method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" - method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only the package." - method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." - 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" - method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." - method_option "frozen", :type => :boolean, :banner => - "Do not allow the Gemfile.lock to be updated after this package operation's install" - long_desc <<-D - The package command will copy the .gem files for every gem in the bundle into the - directory ./vendor/cache. If you then check that directory into your source - control repository, others who check out your source will be able to install the - bundle without having to download any additional gems. - D - def package - require "bundler/cli/package" - Package.new(options).run - end - map %w[pack] => :package - - desc "exec [OPTIONS]", "Run the command in context of the bundle" - method_option :keep_file_descriptors, :type => :boolean, :default => false - long_desc <<-D - 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 - into the system wide RubyGems repository. - D - map "e" => "exec" - def exec(*args) - require "bundler/cli/exec" - Exec.new(options, args).run - end - - desc "config NAME [VALUE]", "Retrieve or set a configuration value" - 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 - existing value with the newly provided one. - - By default, setting a configuration value sets it for all projects - on the machine. - - If a global setting is superceded by local configuration, this command - will show the current value, as well as any superceded values and - where they were specified. - D - method_option "parseable", :type => :boolean, :banner => "Use minimal formatting for more parseable output" - def config(*args) - require "bundler/cli/config" - Config.new(options, args, self).run - end - - desc "open GEM", "Opens the source directory of the given bundled gem" - def open(name) - require "bundler/cli/open" - Open.new(options, name).run - end - - if Bundler.feature_flag.console_command? - desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" - def console(group = nil) - require "bundler/cli/console" - Console.new(options, group).run - end - end - - desc "version", "Prints the bundler's version information" - def 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 - - 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" - def licenses - Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| - gem_name = s.name - license = s.license || s.licenses - - if license.empty? - Bundler.ui.warn "#{gem_name}: Unknown" - else - Bundler.ui.info "#{gem_name}: #{license}" - end - end - end - - desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true - long_desc <<-D - Viz generates a PNG file of the current Gemfile as a dependency graph. - Viz requires the ruby-graphviz gem (and its dependencies). - The associated gems must also be installed via 'bundle install'. - D - method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option" - method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..." - method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency." - method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version." - method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group." - def viz - require "bundler/cli/viz" - Viz.new(options.dup).run - end - - old_gem = instance_method(:gem) - - 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 :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", - :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, - :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" - method_option :ext, :type => :boolean, :default => false, :desc => "Generate the boilerplate for C extension code" - method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config gem.mit true`." - method_option :test, :type => :string, :lazy_default => "rspec", :aliases => "-t", :banner => "rspec", - :desc => "Generate a test directory for your library, either rspec or minitest. Set a default with `bundle config gem.test rspec`." - def gem(name) - end - - commands["gem"].tap do |gem_command| - def gem_command.run(instance, args = []) - arity = 1 # name - - require "bundler/cli/gem" - cmd_args = args + [instance] - cmd_args.unshift(instance.options) - - cmd = begin - Gem.new(*cmd_args) - rescue ArgumentError => e - instance.class.handle_argument_error(self, e, args, arity) - end - - cmd.run - end - end - - undef_method(:gem) - define_method(:gem, old_gem) - private :gem - - def self.source_root - File.expand_path(File.join(File.dirname(__FILE__), "templates")) - end - - desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true - method_option "dry-run", :type => :boolean, :default => false, :banner => - "Only print out changes, do not clean gems" - method_option "force", :type => :boolean, :default => false, :banner => - "Forces clean even if --path is not set" - def clean - require "bundler/cli/clean" - Clean.new(options.dup).run - end - - desc "platform [OPTIONS]", "Displays platform compatibility information" - method_option "ruby", :type => :boolean, :default => false, :banner => - "only display ruby related platform information" - def platform - require "bundler/cli/platform" - Platform.new(options).run - end - - desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true - method_option "source", :type => :string, :banner => - "Install gem from the given source" - method_option "group", :type => :string, :banner => - "Install gem into a bundler group" - def inject(name, version) - SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command" - require "bundler/cli/inject" - Inject.new(options.dup, name, version).run - end - - desc "lock", "Creates a lockfile without installing" - method_option "update", :type => :array, :lazy_default => true, :banner => - "ignore the existing lockfile, update all gems by default, or update list of given gems" - method_option "local", :type => :boolean, :default => false, :banner => - "do not attempt to fetch remote gemspecs and use the local gem cache only" - method_option "print", :type => :boolean, :default => false, :banner => - "print the lockfile to STDOUT instead of writing to the file system" - method_option "lockfile", :type => :string, :default => nil, :banner => - "the path the lockfile should be written to" - method_option "full-index", :type => :boolean, :default => false, :banner => - "Fall back to using the single-file index of all gems" - method_option "add-platform", :type => :array, :default => [], :banner => - "Add a new platform to the lockfile" - method_option "remove-platform", :type => :array, :default => [], :banner => - "Remove a platform from the lockfile" - method_option "patch", :type => :boolean, :banner => - "If updating, prefer updating only to next patch version" - method_option "minor", :type => :boolean, :banner => - "If updating, prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => - "If updating, prefer updating to next major version (default)" - method_option "strict", :type => :boolean, :banner => - "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "conservative", :type => :boolean, :banner => - "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" - def lock - require "bundler/cli/lock" - Lock.new(options).run - end - - desc "env", "Print information about the environment Bundler is running under" - def env - Env.write($stdout) - end - - desc "doctor [OPTIONS]", "Checks the bundle for common problems" - long_desc <<-D - Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If - missing dependencies are detected, Bundler prints them and exits status 1. - Otherwise, Bundler prints a success message and exits with a status of 0. - D - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - def doctor - require "bundler/cli/doctor" - Doctor.new(options).run - end - - desc "issue", "Learn how to report an issue in Bundler" - def issue - require "bundler/cli/issue" - Issue.new.run - end - - desc "pristine [GEMS...]", "Restores installed gems to pristine condition" - 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" - Pristine.new(gems).run - end - - if Bundler.feature_flag.plugins? - require "bundler/cli/plugin" - desc "plugin", "Manage the bundler plugins" - subcommand "plugin", Plugin - end - - # Reformat the arguments passed to bundle that include a --help flag - # into the corresponding `bundle help #{command}` call - def self.reformatted_help_args(args) - bundler_commands = all_commands.keys - help_flags = %w[--help -h] - exec_commands = %w[e ex exe exec] - help_used = args.index {|a| help_flags.include? a } - exec_used = args.index {|a| exec_commands.include? a } - command = args.find {|a| bundler_commands.include? a } - if exec_used && help_used - if exec_used + help_used == 1 - %w[help exec] - else - args - end - elsif help_used - args = args.dup - args.delete_at(help_used) - ["help", command || args].flatten.compact - else - args - end - end - - private - - # Automatically invoke `bundle install` and resume if - # Bundler.settings[:auto_install] exists. This is set through config cmd - # `bundle config auto_install 1`. - # - # Note that this method `nil`s out the global Definition object, so it - # should be called first, before you instantiate anything like an - # `Installer` that'll keep a reference to the old one instead. - def auto_install - return unless Bundler.settings[:auto_install] - - begin - Bundler.definition.specs - rescue GemNotFound - Bundler.ui.info "Automatically installing missing gems." - Bundler.reset! - invoke :install, [] - Bundler.reset! - end - end - - def current_command - _, _, config = @_initializer - config[:current_command] - end - - def print_command - return unless Bundler.ui.debug? - cmd = current_command - command_name = cmd.name - return if PARSEABLE_COMMANDS.include?(command_name) - command = ["bundle", command_name] + args - options_to_print = options.dup - options_to_print.delete_if do |k, v| - next unless o = cmd.options[k] - o.default == v - end - command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip - command.reject!(&:empty?) - Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}" - end - - def warn_on_outdated_bundler - return if Bundler.settings[:disable_version_check] - - command_name = current_command.name - return if PARSEABLE_COMMANDS.include?(command_name) - - latest = Fetcher::CompactIndex. - new(nil, Source::Rubygems::Remote.new(URI("https://rubygems.org")), nil). - send(:compact_index_client). - instance_variable_get(:@cache). - dependencies("bundler"). - map {|d| Gem::Version.new(d.first) }. - max - return unless latest - - current = Gem::Version.new(VERSION) - return if current >= latest - latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max - - 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 - nil - end - end -end diff --git a/lib/bundler/cli/add.rb b/lib/bundler/cli/add.rb deleted file mode 100644 index 1fcbd22f28..0000000000 --- a/lib/bundler/cli/add.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Add - def initialize(options, gem_name) - @gem_name = gem_name - @options = options - @options[:group] = @options[:group].split(",").map(&:strip) if !@options[:group].nil? && !@options[:group].empty? - end - - def run - version = @options[:version].nil? ? nil : @options[:version].split(",").map(&:strip) - - unless version.nil? - version.each do |v| - raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s - end - end - dependency = Bundler::Dependency.new(@gem_name, version, @options) - - Injector.inject([dependency], :conservative_versioning => @options[:version].nil?) # Perform conservative versioning only when version is not specified - Installer.install(Bundler.root, Bundler.definition) - end - end -end diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb deleted file mode 100644 index 449204d821..0000000000 --- a/lib/bundler/cli/binstubs.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Binstubs - attr_reader :options, :gems - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - Bundler.definition.validate_runtime! - path_option = options["path"] - 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) - - if gems.empty? - Bundler.ui.error "`bundle binstubs` needs at least one gem to run." - exit 1 - end - - gems.each do |gem_name| - spec = Bundler.definition.specs.find {|s| s.name == gem_name } - unless spec - raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( - gem_name, Bundler.definition.specs - ) - end - - if options[:standalone] - next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" - Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do - installer.generate_standalone_bundler_executable_stubs(spec) - end - else - installer.generate_bundler_executable_stubs(spec, :force => options[:force], :binstubs_cmd => true) - end - end - end - end -end diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb deleted file mode 100644 index 9d2ba87d34..0000000000 --- a/lib/bundler/cli/cache.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Cache - attr_reader :options - def initialize(options) - @options = options - end - - def run - Bundler.definition.validate_runtime! - Bundler.definition.resolve_with_cache! - setup_cache_all - Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"] - Bundler.load.cache - Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] - Bundler.load.lock - rescue GemNotFound => e - Bundler.ui.error(e.message) - Bundler.ui.warn "Run `bundle install` to install missing gems." - exit 1 - end - - private - - def setup_cache_all - Bundler.settings.set_command_option_if_given :cache_all, options[: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 " \ - "to package them as well, please pass the --all flag. This will be the default " \ - "on Bundler 2.0." - end - end - end -end diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb deleted file mode 100644 index e572787dc4..0000000000 --- a/lib/bundler/cli/check.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Check - attr_reader :options - - def initialize(options) - @options = options - end - - def run - Bundler.settings.set_command_option_if_given :path, options[:path] - - begin - definition = Bundler.definition - definition.validate_runtime! - not_installed = definition.missing_specs - rescue GemNotFound, VersionConflict - Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." - Bundler.ui.warn "Install missing gems with `bundle install`." - exit 1 - end - - if not_installed.any? - Bundler.ui.error "The following gems are missing" - not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } - Bundler.ui.warn "Install missing gems with `bundle install`" - exit 1 - 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" - exit 1 - else - Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] - Bundler.ui.info "The Gemfile's dependencies are satisfied" - end - end - end -end diff --git a/lib/bundler/cli/clean.rb b/lib/bundler/cli/clean.rb deleted file mode 100644 index 4a407fbae7..0000000000 --- a/lib/bundler/cli/clean.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Clean - attr_reader :options - - def initialize(options) - @options = options - end - - def run - require_path_or_force unless options[:"dry-run"] - Bundler.load.clean(options[:"dry-run"]) - end - - protected - - def require_path_or_force - return unless Bundler.use_system_gems? && !options[:force] - 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 " \ - "bundle, run `bundle clean --force`." - end - end -end diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb deleted file mode 100644 index 9d40ee9dfd..0000000000 --- a/lib/bundler/cli/common.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module CLI::Common - def self.output_post_install_messages(messages) - return if Bundler.settings["ignore_messages"] - messages.to_a.each do |name, msg| - print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] - end - end - - def self.print_post_install_message(name, msg) - Bundler.ui.confirm "Post-install message from #{name}:" - Bundler.ui.info msg - end - - def self.output_without_groups_message - return if Bundler.settings[:without].empty? - Bundler.ui.confirm without_groups_message - end - - def self.without_groups_message - groups = Bundler.settings[:without] - group_list = [groups[0...-1].join(", "), groups[-1..-1]]. - reject {|s| s.to_s.empty? }.join(" and ") - group_str = (groups.size == 1) ? "group" : "groups" - "Gems in the #{group_str} #{group_list} were not installed." - end - - def self.select_spec(name, regex_match = nil) - specs = [] - regexp = Regexp.new(name) if regex_match - - Bundler.definition.specs.each do |spec| - return spec if spec.name == name - specs << spec if regexp && spec.name =~ regexp - end - - case specs.count - when 0 - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - when 1 - specs.first - else - ask_for_spec_from(specs) - end - rescue RegexpError - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - end - - def self.ask_for_spec_from(specs) - if !$stdout.tty? && ENV["BUNDLE_SPEC_RUN"].nil? - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - end - - specs.each_with_index do |spec, index| - Bundler.ui.info "#{index.succ} : #{spec.name}", true - end - Bundler.ui.info "0 : - exit -", true - - num = Bundler.ui.ask("> ").to_i - num > 0 ? specs[num - 1] : nil - end - - def self.gem_not_found_message(missing_gem_name, alternatives) - require "bundler/similarity_detector" - message = "Could not find gem '#{missing_gem_name}'." - alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } - suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) - message += "\nDid you mean #{suggestions}?" if suggestions - message - end - - def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) - locked_names = locked_gems.specs.map(&:name) - names.-(locked_names).each do |g| - raise GemNotFound, gem_not_found_message(g, locked_names) - end - end - - def self.configure_gem_version_promoter(definition, options) - patch_level = patch_level_options(options) - raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 - definition.gem_version_promoter.tap do |gvp| - gvp.level = patch_level.first || :major - gvp.strict = options[:strict] || options["update-strict"] - end - end - - def self.patch_level_options(options) - [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } - 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 diff --git a/lib/bundler/cli/config.rb b/lib/bundler/cli/config.rb deleted file mode 100644 index 12f71ea8fe..0000000000 --- a/lib/bundler/cli/config.rb +++ /dev/null @@ -1,119 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Config - attr_reader :name, :options, :scope, :thor - attr_accessor :args - - def initialize(options, args, thor) - @options = options - @args = args - @thor = thor - @name = peek = args.shift - @scope = "global" - return unless peek && peek.start_with?("--") - @name = args.shift - @scope = peek[2..-1] - end - - def run - unless name - confirm_all - return - end - - unless valid_scope?(scope) - Bundler.ui.error "Invalid scope --#{scope} given. Please use --local or --global." - exit 1 - end - - if scope == "delete" - Bundler.settings.set_local(name, nil) - Bundler.settings.set_global(name, nil) - return - end - - if args.empty? - if options[:parseable] - if value = Bundler.settings[name] - Bundler.ui.info("#{name}=#{value}") - end - return - end - - confirm(name) - return - end - - Bundler.ui.info(message) if message - Bundler.settings.send("set_#{scope}", name, new_value) - end - - private - - def confirm_all - if @options[:parseable] - thor.with_padding do - Bundler.settings.all.each do |setting| - val = Bundler.settings[setting] - Bundler.ui.info "#{setting}=#{val}" - end - end - else - Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" - Bundler.settings.all.each do |setting| - Bundler.ui.confirm "#{setting}" - show_pretty_values_for(setting) - Bundler.ui.confirm "" - end - end - end - - def confirm(name) - Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" - show_pretty_values_for(name) - end - - def new_value - pathname = Pathname.new(args.join(" ")) - if name.start_with?("local.") && pathname.directory? - pathname.expand_path.to_s - else - args.join(" ") - end - end - - def message - locations = Bundler.settings.locations(name) - if @options[:parseable] - "#{name}=#{new_value}" if new_value - elsif scope == "global" - if locations[:local] - "Your application has set #{name} to #{locations[:local].inspect}. " \ - "This will override the global value you are currently setting" - elsif locations[:env] - "You have a bundler environment variable for #{name} set to " \ - "#{locations[:env].inspect}. This will take precedence over the global value you are setting" - elsif locations[:global] && locations[:global] != args.join(" ") - "You are replacing the current global value of #{name}, which is currently " \ - "#{locations[:global].inspect}" - end - elsif scope == "local" && locations[:local] != args.join(" ") - "You are replacing the current local value of #{name}, which is currently " \ - "#{locations[:local].inspect}" - end - end - - def show_pretty_values_for(setting) - thor.with_padding do - Bundler.settings.pretty_values_for(setting).each do |line| - Bundler.ui.info line - end - end - end - - def valid_scope?(scope) - %w[delete local global].include?(scope) - end - end -end diff --git a/lib/bundler/cli/console.rb b/lib/bundler/cli/console.rb deleted file mode 100644 index 853eca8358..0000000000 --- a/lib/bundler/cli/console.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Console - attr_reader :options, :group - def initialize(options, group) - @options = options - @group = group - end - - def run - Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \ - "by `bin/console` generated by `bundle gem <name>`" - - group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require - ARGV.clear - - console = get_console(Bundler.settings[:console] || "irb") - console.start - end - - def get_console(name) - require name - get_constant(name) - rescue LoadError - Bundler.ui.error "Couldn't load console #{name}, falling back to irb" - require "irb" - get_constant("irb") - end - - def get_constant(name) - const_name = { - "pry" => :Pry, - "ripl" => :Ripl, - "irb" => :IRB, - }[name] - Object.const_get(const_name) - rescue NameError - Bundler.ui.error "Could not find constant #{const_name}" - exit 1 - end - end -end diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb deleted file mode 100644 index 7f28a5eb13..0000000000 --- a/lib/bundler/cli/doctor.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -require "rbconfig" - -module Bundler - class CLI::Doctor - DARWIN_REGEX = /\s+(.+) \(compatibility / - LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/ - - attr_reader :options - - def initialize(options) - @options = options - end - - def otool_available? - Bundler.which("otool") - end - - def ldd_available? - Bundler.which("ldd") - end - - def dylibs_darwin(path) - output = `/usr/bin/otool -L "#{path}"`.chomp - dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq - # ignore @rpath and friends - dylibs.reject {|dylib| dylib.start_with? "@" } - end - - def dylibs_ldd(path) - output = `/usr/bin/ldd "#{path}"`.chomp - output.split("\n").map do |l| - match = l.match(LDD_REGEX) - next if match.nil? - match.captures[0] - end.compact - end - - def dylibs(path) - case RbConfig::CONFIG["host_os"] - when /darwin/ - return [] unless otool_available? - dylibs_darwin(path) - when /(linux|solaris|bsd)/ - return [] unless ldd_available? - dylibs_ldd(path) - else # Windows, etc. - Bundler.ui.warn("Dynamic library check not supported on this platform.") - [] - end - end - - def bundles_for_gem(spec) - Dir.glob("#{spec.full_gem_path}/**/*.bundle") - end - - def check! - require "bundler/cli/check" - Bundler::CLI::Check.new({}).run - end - - def run - Bundler.ui.level = "error" if options[:quiet] - Bundler.settings.validate! - check! - - definition = Bundler.definition - broken_links = {} - - definition.specs.each do |spec| - bundles_for_gem(spec).each do |bundle| - bad_paths = dylibs(bundle).select {|f| !File.exist?(f) } - if bad_paths.any? - broken_links[spec] ||= [] - broken_links[spec].concat(bad_paths) - end - end - end - - if broken_links.any? - message = "The following gems are missing OS dependencies:" - broken_links.map do |spec, paths| - paths.uniq.map do |path| - "\n * #{spec.name}: #{path}" - end - end.flatten.sort.each {|m| message += m } - raise ProductionError, message - else - Bundler.ui.info "No issues found with the installed bundle" - end - end - end -end diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb deleted file mode 100644 index 2fdc614fbb..0000000000 --- a/lib/bundler/cli/exec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# frozen_string_literal: true - -require "bundler/current_ruby" - -module Bundler - class CLI::Exec - attr_reader :options, :args, :cmd - - RESERVED_SIGNALS = %w[SEGV BUS ILL FPE VTALRM KILL STOP].freeze - - def initialize(options, args) - @options = options - @cmd = args.shift - @args = args - - if Bundler.current_ruby.ruby_2? && !Bundler.current_ruby.jruby? - @args << { :close_others => !options.keep_file_descriptors? } - elsif options.keep_file_descriptors? - Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." - end - end - - def run - validate_cmd! - SharedHelpers.set_bundle_environment - if bin_path = Bundler.which(cmd) - if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) - return kernel_load(bin_path, *args) - end - # First, try to exec directly to something in PATH - if Bundler.current_ruby.jruby_18? - kernel_exec(bin_path, *args) - else - kernel_exec([bin_path, cmd], *args) - end - else - # exec using the given command - kernel_exec(cmd, *args) - end - end - - private - - def validate_cmd! - return unless cmd.nil? - Bundler.ui.error "bundler: exec needs a command to run" - exit 128 - end - - def kernel_exec(*args) - ui = Bundler.ui - Bundler.ui = nil - Kernel.exec(*args) - rescue Errno::EACCES, Errno::ENOEXEC - Bundler.ui = ui - Bundler.ui.error "bundler: not executable: #{cmd}" - exit 126 - rescue Errno::ENOENT - Bundler.ui = ui - Bundler.ui.error "bundler: command not found: #{cmd}" - Bundler.ui.warn "Install missing gem executables with `bundle install`" - exit 127 - end - - def kernel_load(file, *args) - args.pop if args.last.is_a?(Hash) - ARGV.replace(args) - $0 = file - Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) - ui = Bundler.ui - Bundler.ui = nil - require "bundler/setup" - signals = Signal.list.keys - RESERVED_SIGNALS - signals.each {|s| trap(s, "DEFAULT") } - Kernel.load(file) - rescue SystemExit, SignalException - raise - rescue Exception => e # rubocop:disable Lint/RescueException - Bundler.ui = ui - Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" - backtrace = e.backtrace.take_while {|bt| !bt.start_with?(__FILE__) } - abort "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}" - end - - def process_title(file, args) - "#{file} #{args.join(" ")}".strip - end - - def ruby_shebang?(file) - possibilities = [ - "#!/usr/bin/env ruby\n", - "#!/usr/bin/env jruby\n", - "#!#{Gem.ruby}\n", - ] - - if File.zero?(file) - Bundler.ui.warn "#{file} is empty" - return false - end - - first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } - possibilities.any? {|shebang| first_line.start_with?(shebang) } - end - end -end diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb deleted file mode 100644 index 885578e819..0000000000 --- a/lib/bundler/cli/gem.rb +++ /dev/null @@ -1,249 +0,0 @@ -# frozen_string_literal: true - -require "pathname" - -module Bundler - class CLI - Bundler.require_thor_actions - include Thor::Actions - end - - class CLI::Gem - TEST_FRAMEWORK_VERSIONS = { - "rspec" => "3.0", - "minitest" => "5.0" - }.freeze - - attr_reader :options, :gem_name, :thor, :name, :target - - def initialize(options, gem_name, thor) - @options = options - @gem_name = resolve_name(gem_name) - - @thor = thor - thor.behavior = :invoke - thor.destination_root = nil - - @name = @gem_name - @target = SharedHelpers.pwd.join(gem_name) - - validate_ext_name if options[:ext] - end - - def run - Bundler.ui.confirm "Creating gem '#{name}'..." - - underscored_name = name.tr("-", "_") - namespaced_path = name.tr("-", "/") - constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } - constant_array = constant_name.split("::") - - git_installed = Bundler.git_present? - - git_author_name = git_installed ? `git config user.name`.chomp : "" - github_username = git_installed ? `git config github.user`.chomp : "" - git_user_email = git_installed ? `git config user.email`.chomp : "" - - config = { - :name => name, - :underscored_name => underscored_name, - :namespaced_path => namespaced_path, - :makefile_path => "#{underscored_name}/#{underscored_name}", - :constant_name => constant_name, - :constant_array => constant_array, - :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name, - :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, - :test => options[:test], - :ext => options[:ext], - :exe => options[:exe], - :bundler_version => bundler_dependency_version, - :github_username => github_username.empty? ? "[USERNAME]" : github_username - } - ensure_safe_gem_name(name, constant_array) - - templates = { - "Gemfile.tt" => "Gemfile", - "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", - "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", - "newgem.gemspec.tt" => "#{name}.gemspec", - "Rakefile.tt" => "Rakefile", - "README.md.tt" => "README.md", - "bin/console.tt" => "bin/console", - "bin/setup.tt" => "bin/setup" - } - - executables = %w[ - bin/console - bin/setup - ] - - templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present? - - if test_framework = ask_and_set_test_framework - config[:test] = test_framework - config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] - - templates.merge!("travis.yml.tt" => ".travis.yml") - - case test_framework - when "rspec" - templates.merge!( - "rspec.tt" => ".rspec", - "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", - "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" - ) - when "minitest" - templates.merge!( - "test/test_helper.rb.tt" => "test/test_helper.rb", - "test/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" - ) - end - end - - config[:test_task] = config[:test] == "minitest" ? "test" : "spec" - - if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", - "This means that any other developer or company will be legally allowed to use your code " \ - "for free as long as they admit you created it. You can read more about the MIT license " \ - "at http://choosealicense.com/licenses/mit.") - config[:mit] = true - Bundler.ui.info "MIT License enabled in config" - templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") - end - - if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", - "Codes of conduct can increase contributions to your project by contributors who " \ - "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ - "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ - "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ - "address is specified as a contact in the generated code of conduct so that people know " \ - "who to contact in case of a violation. For suggestions about " \ - "how to enforce codes of conduct, see http://bit.ly/coc-enforcement.") - config[:coc] = true - Bundler.ui.info "Code of conduct enabled in config" - templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") - end - - templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] - - if options[:ext] - templates.merge!( - "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", - "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", - "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" - ) - end - - templates.each do |src, dst| - destination = target.join(dst) - SharedHelpers.filesystem_access(destination) do - thor.template("newgem/#{src}", destination, config) - end - end - - executables.each do |file| - SharedHelpers.filesystem_access(target.join(file)) do |path| - executable = (path.stat.mode | 0o111) - path.chmod(executable) - end - end - - if Bundler.git_present? - Bundler.ui.info "Initializing git repo in #{target}" - Dir.chdir(target) do - `git init` - `git add .` - end - end - - # Open gemspec in editor - open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] - rescue Errno::EEXIST => e - raise GenericSystemCallError.new(e, "There was a conflict while creating the new gem.") - end - - private - - def resolve_name(name) - SharedHelpers.pwd.join(name).basename.to_s - end - - def ask_and_set(key, header, message) - choice = options[key] - choice = Bundler.settings["gem.#{key}"] if choice.nil? - - if choice.nil? - Bundler.ui.confirm header - choice = Bundler.ui.yes? "#{message} y/(n):" - Bundler.settings.set_global("gem.#{key}", choice) - end - - choice - end - - def validate_ext_name - return unless gem_name.index("-") - - Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ - "naming guidelines for C extensions. For more information, \n" \ - "see the 'Extension Naming' section at the following URL:\n" \ - "http://guides.rubygems.org/gems-with-extensions/\n" - exit 1 - end - - def ask_and_set_test_framework - test_framework = options[:test] || Bundler.settings["gem.test"] - - if test_framework.nil? - Bundler.ui.confirm "Do you want to generate tests with your gem?" - result = Bundler.ui.ask "Type 'rspec' or 'minitest' to generate those test files now and " \ - "in the future. rspec/minitest/(none):" - if result =~ /rspec|minitest/ - test_framework = result - else - test_framework = false - end - end - - if Bundler.settings["gem.test"].nil? - Bundler.settings.set_global("gem.test", test_framework) - end - - test_framework - end - - def bundler_dependency_version - v = Gem::Version.new(Bundler::VERSION) - req = v.segments[0..1] - req << "a" if v.prerelease? - req.join(".") - end - - def ensure_safe_gem_name(name, constant_array) - if name =~ /^\d/ - Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." - exit 1 - end - - constant_name = constant_array.join("::") - - existing_constant = constant_array.inject(Object) do |c, s| - defined = begin - c.const_defined?(s) - rescue NameError - Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" - exit 1 - end - (defined && c.const_get(s)) || break - end - - return unless existing_constant - Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." - exit 1 - end - - def open_editor(editor, file) - thor.run(%(#{editor} "#{file}")) - end - end -end diff --git a/lib/bundler/cli/info.rb b/lib/bundler/cli/info.rb deleted file mode 100644 index 958b525067..0000000000 --- a/lib/bundler/cli/info.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Info - attr_reader :gem_name, :options - def initialize(options, gem_name) - @options = options - @gem_name = gem_name - end - - def run - spec = spec_for_gem(gem_name) - - spec_not_found(gem_name) unless spec - return print_gem_path(spec) if @options[:path] - print_gem_info(spec) - end - - private - - def spec_for_gem(gem_name) - spec = Bundler.definition.specs.find {|s| s.name == gem_name } - spec || default_gem_spec(gem_name) - end - - def default_gem_spec(gem_name) - return unless Gem::Specification.respond_to?(:find_all_by_name) - gem_spec = Gem::Specification.find_all_by_name(gem_name).last - return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? - end - - def spec_not_found(gem_name) - raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) - end - - def print_gem_path(spec) - Bundler.ui.info spec.full_gem_path - end - - def print_gem_info(spec) - gem_info = String.new - gem_info << " * #{spec.name} (#{spec.version}#{spec.git_version})\n" - gem_info << "\tSummary: #{spec.summary}\n" if spec.summary - gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage - gem_info << "\tPath: #{spec.full_gem_path}\n" - gem_info << "\tDefault Gem: yes" if spec.respond_to?(:default_gem?) && spec.default_gem? - Bundler.ui.info gem_info - end - end -end diff --git a/lib/bundler/cli/init.rb b/lib/bundler/cli/init.rb deleted file mode 100644 index fa53e7c74b..0000000000 --- a/lib/bundler/cli/init.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Init - attr_reader :options - def initialize(options) - @options = options - end - - def run - if File.exist?(gemfile) - Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" - exit 1 - end - - if options[:gemspec] - gemspec = File.expand_path(options[:gemspec]) - unless File.exist?(gemspec) - Bundler.ui.error "Gem specification #{gemspec} doesn't exist" - exit 1 - end - - spec = Bundler.load_gemspec_uncached(gemspec) - - File.open(gemfile, "wb") do |file| - file << "# Generated from #{gemspec}\n" - file << spec.to_gemfile - end - else - FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile) - end - - puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" - end - - private - - def gemfile - @gemfile ||= Bundler.feature_flag.init_gems_rb? ? "gems.rb" : "Gemfile" - end - end -end diff --git a/lib/bundler/cli/inject.rb b/lib/bundler/cli/inject.rb deleted file mode 100644 index b00675d348..0000000000 --- a/lib/bundler/cli/inject.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Inject - attr_reader :options, :name, :version, :group, :source, :gems - def initialize(options, name, version) - @options = options - @name = name - @version = version || last_version_number - @group = options[:group].split(",") unless options[:group].nil? - @source = options[:source] - @gems = [] - end - - def run - # The required arguments allow Thor to give useful feedback when the arguments - # are incorrect. This adds those first two arguments onto the list as a whole. - gems.unshift(source).unshift(group).unshift(version).unshift(name) - - # Build an array of Dependency objects out of the arguments - deps = [] - # when `inject` support addition of more than one gem, then this loop will - # help. Currently this loop is running once. - gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| - ops = Gem::Requirement::OPS.map {|key, _val| key } - has_op = ops.any? {|op| gem_version.start_with? op } - gem_version = "~> #{gem_version}" unless has_op - deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) - end - - added = Injector.inject(deps, options) - - if added.any? - Bundler.ui.confirm "Added to Gemfile:" - Bundler.ui.confirm(added.map do |d| - name = "'#{d.name}'" - requirement = ", '#{d.requirement}'" - group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) - source = ", :source => '#{d.source}'" unless d.source.nil? - %(gem #{name}#{requirement}#{group}#{source}) - end.join("\n")) - else - Bundler.ui.confirm "All gems were already present in the Gemfile" - end - end - - private - - def last_version_number - definition = Bundler.definition(true) - definition.resolve_remotely! - specs = definition.index[name].sort_by(&:version) - unless options[:pre] - specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - spec = specs.last - spec.version.to_s - end - end -end diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb deleted file mode 100644 index f0b821ed84..0000000000 --- a/lib/bundler/cli/install.rb +++ /dev/null @@ -1,214 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Install - attr_reader :options - def initialize(options) - @options = options - end - - def run - Bundler.ui.level = "error" if options[:quiet] - - warn_if_root - - normalize_groups - - Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD - - # Disable color in deployment mode - Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] - - check_for_options_conflicts - - check_trust_policy - - if options[:deployment] || options[:frozen] || Bundler.frozen? - unless Bundler.default_lockfile.exist? - flag = "--deployment flag" if options[:deployment] - 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 " \ - "before deploying." - end - - options[:local] = true if Bundler.app_cache.exist? - - if Bundler.feature_flag.deployment_means_frozen? - Bundler.settings.set_command_option :deployment, true - else - Bundler.settings.set_command_option :frozen, true - end - end - - # When install is called with --no-deployment, disable deployment mode - if options[:deployment] == false - Bundler.settings.set_command_option :frozen, nil - options[:system] = true - end - - normalize_settings - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - if options["binstubs"] - Bundler::SharedHelpers.major_deprecation 2, - "The --binstubs option will be removed in favor of `bundle binstubs`" - end - - Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? - - definition = Bundler.definition - definition.validate_runtime! - - installer = Installer.install(Bundler.root, definition, options) - 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::CLI::Common.output_without_groups_message - - if Bundler.use_system_gems? - 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 - - Bundler::CLI::Common.output_post_install_messages installer.post_install_messages - - warn_ambiguous_gems - - if CLI::Common.clean_after_install? - require "bundler/cli/clean" - Bundler::CLI::Clean.new(options).run - end - rescue GemNotFound, VersionConflict => e - if options[:local] && Bundler.app_cache.exist? - Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." - end - - unless Bundler.definition.has_rubygems_remotes? - Bundler.ui.warn <<-WARN, :wrap => true - Your Gemfile has no gem server sources. If you need gems that are \ - not already on your machine, add a line like this to your Gemfile: - source 'https://rubygems.org' - WARN - end - raise e - rescue Gem::InvalidSpecificationException => e - Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." - raise e - end - - private - - def warn_if_root - return if Bundler.settings[:silence_root_warning] || Bundler::WINDOWS || !Process.uid.zero? - Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ - "if it is needed, and installing your bundle as root will break this " \ - "application for all non-root users on this machine.", :wrap => true - end - - def dependencies_count_for(definition) - count = definition.dependencies.count - "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" - end - - def gems_installed_for(definition) - count = definition.specs.count - "#{count} #{count == 1 ? "gem" : "gems"} now installed" - end - - def check_for_group_conflicts_in_cli_options - conflicting_groups = Array(options[:without]) & Array(options[:with]) - return if conflicting_groups.empty? - raise InvalidOption, "You can't list a group in both with and without." \ - " The offending groups are: #{conflicting_groups.join(", ")}." - end - - def check_for_options_conflicts - if (options[:path] || options[:deployment]) && options[:system] - error_message = String.new - error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] - error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] - raise InvalidOption.new(error_message) - end - end - - def check_trust_policy - trust_policy = options["trust-policy"] - unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) - raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ - "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." - end - Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy - end - - def normalize_groups - options[:with] &&= options[:with].join(":").tr(" ", ":").split(":") - options[:without] &&= options[:without].join(":").tr(" ", ":").split(":") - - check_for_group_conflicts_in_cli_options - - 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] - - without = options.fetch(:without, []) - without |= Bundler.settings[:without].map(&:to_s) - without -= options[:with] if options[:with] - - options[:with] = with - options[:without] = without - end - - def normalize_settings - Bundler.settings.set_command_option :path, nil if options[:system] - Bundler.settings.set_command_option :path, "vendor/bundle" if options[:deployment] - Bundler.settings.set_command_option_if_given :path, options["path"] - Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? - - bin_option = options["binstubs"] - bin_option = nil if bin_option && bin_option.empty? - Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] - - Bundler.settings.set_command_option_if_given :shebang, options["shebang"] - - Bundler.settings.set_command_option_if_given :jobs, options["jobs"] - - Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] - - Bundler.settings.set_command_option_if_given :no_install, options["no-install"] - - Bundler.settings.set_command_option_if_given :clean, options["clean"] - - unless Bundler.settings[:without] == options[:without] && 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 - - options[:force] = options[:redownload] - end - - def warn_ambiguous_gems - Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| - Bundler.ui.error "Warning: the gem '#{name}' was found in multiple sources." - Bundler.ui.error "Installed from: #{installed_from_uri}" - Bundler.ui.error "Also found in:" - also_found_in_uris.each {|uri| Bundler.ui.error " * #{uri}" } - Bundler.ui.error "You should add a source requirement to restrict this gem to your preferred source." - Bundler.ui.error "For example:" - Bundler.ui.error " gem '#{name}', :source => '#{installed_from_uri}'" - Bundler.ui.error "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." - end - end - end -end diff --git a/lib/bundler/cli/issue.rb b/lib/bundler/cli/issue.rb deleted file mode 100644 index 91f827ea99..0000000000 --- a/lib/bundler/cli/issue.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require "rbconfig" - -module Bundler - class CLI::Issue - def run - Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") - Did you find an issue with Bundler? Before filing a new issue, - be sure to check out these resources: - - 1. Check out our troubleshooting guide for quick fixes to common issues: - https://github.com/bundler/bundler/blob/master/doc/TROUBLESHOOTING.md - - 2. Instructions for common Bundler uses can be found on the documentation - site: http://bundler.io/ - - 3. Information about each Bundler command can be found in the Bundler - man pages: http://bundler.io/man/bundle.1.html - - Hopefully the troubleshooting steps above resolved your problem! If things - still aren't working the way you expect them to, please let us know so - that we can diagnose and help fix the problem you're having. Please - view the Filing Issues guide for more information: - https://github.com/bundler/bundler/blob/master/doc/contributing/ISSUES.md - - EOS - - Bundler.ui.info Bundler::Env.report - - Bundler.ui.info "\n## Bundle Doctor" - doctor - end - - def doctor - require "bundler/cli/doctor" - Bundler::CLI::Doctor.new({}).run - end - end -end diff --git a/lib/bundler/cli/list.rb b/lib/bundler/cli/list.rb deleted file mode 100644 index b5e7c1e650..0000000000 --- a/lib/bundler/cli/list.rb +++ /dev/null @@ -1,22 +0,0 @@ -# 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 diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb deleted file mode 100644 index 7dd078b1ef..0000000000 --- a/lib/bundler/cli/lock.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Lock - attr_reader :options - - def initialize(options) - @options = options - end - - def run - unless Bundler.default_gemfile - Bundler.ui.error "Unable to find a Gemfile to lock" - exit 1 - end - - print = options[:print] - ui = Bundler.ui - Bundler.ui = UI::Silent.new if print - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - update = options[:update] - if update.is_a?(Array) # unlocking specific gems - Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) - update = { :gems => update, :lock_shared_dependencies => options[:conservative] } - end - definition = Bundler.definition(update) - - Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] - - options["remove-platform"].each do |platform| - definition.remove_platform(platform) - end - - options["add-platform"].each do |platform_string| - platform = Gem::Platform.new(platform_string) - if platform.to_s == "unknown" - Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ - "and adding it will likely lead to resolution errors" - end - definition.add_platform(platform) - end - - if definition.platforms.empty? - raise InvalidOption, "Removing all platforms from the bundle is not allowed" - end - - definition.resolve_remotely! unless options[:local] - - if print - puts definition.to_lock - else - file = options[:lockfile] - file = file ? File.expand_path(file) : Bundler.default_lockfile - puts "Writing lockfile to #{file}" - definition.lock(file) - end - - Bundler.ui = ui - end - end -end diff --git a/lib/bundler/cli/open.rb b/lib/bundler/cli/open.rb deleted file mode 100644 index 552fe6f128..0000000000 --- a/lib/bundler/cli/open.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require "shellwords" - -module Bundler - class CLI::Open - attr_reader :options, :name - def initialize(options, name) - @options = options - @name = name - end - - def run - editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } - return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor - return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) - path = spec.full_gem_path - Dir.chdir(path) do - command = Shellwords.split(editor) + [path] - Bundler.with_original_env do - system(*command) - end || Bundler.ui.info("Could not run '#{command.join(" ")}'") - end - end - end -end diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb deleted file mode 100644 index 5125cc710b..0000000000 --- a/lib/bundler/cli/outdated.rb +++ /dev/null @@ -1,260 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Outdated - attr_reader :options, :gems - - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - check_for_deployment_mode - - sources = Array(options[:source]) - - gems.each do |gem_name| - Bundler::CLI::Common.select_spec(gem_name) - end - - Bundler.definition.validate_runtime! - current_specs = Bundler.ui.silence { Bundler.definition.resolve } - current_dependencies = {} - Bundler.ui.silence do - Bundler.load.dependencies.each do |dep| - current_dependencies[dep.name] = dep - end - end - - definition = if gems.empty? && sources.empty? - # We're doing a full update - Bundler.definition(true) - else - Bundler.definition(:gems => gems, :sources => sources) - end - - Bundler::CLI::Common.configure_gem_version_promoter( - Bundler.definition, - options - ) - - # the patch level options imply strict is also true. It wouldn't make - # sense otherwise. - strict = options[:strict] || - Bundler::CLI::Common.patch_level_options(options).any? - - filter_options_patch = options.keys & - %w[filter-major filter-minor filter-patch] - - definition_resolution = proc do - options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! - end - - if options[:parseable] - Bundler.ui.silence(&definition_resolution) - else - definition_resolution.call - end - - Bundler.ui.info "" - outdated_gems_by_groups = {} - outdated_gems_list = [] - - # Loop through the current specs - gemfile_specs, dependency_specs = current_specs.partition do |spec| - current_dependencies.key? spec.name - end - - (gemfile_specs + dependency_specs).sort_by(&:name).each do |current_spec| - next if !gems.empty? && !gems.include?(current_spec.name) - - dependency = current_dependencies[current_spec.name] - active_spec = retrieve_active_spec(strict, definition, current_spec) - - next if active_spec.nil? - if filter_options_patch.any? - update_present = update_present_via_semver_portions(current_spec, active_spec, options) - next unless update_present - end - - gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) - next unless gem_outdated || (current_spec.git_version != active_spec.git_version) - groups = nil - if dependency && !options[:parseable] - groups = dependency.groups.join(", ") - end - - outdated_gems_list << { :active_spec => active_spec, - :current_spec => current_spec, - :dependency => dependency, - :groups => groups } - - outdated_gems_by_groups[groups] ||= [] - outdated_gems_by_groups[groups] << { :active_spec => active_spec, - :current_spec => current_spec, - :dependency => dependency, - :groups => groups } - end - - if outdated_gems_list.empty? - display_nothing_outdated_message(filter_options_patch) - else - unless options[:parseable] - if options[:pre] - Bundler.ui.info "Outdated gems included in the bundle (including " \ - "pre-releases):" - else - Bundler.ui.info "Outdated gems included in the bundle:" - end - end - - options_include_groups = [:group, :groups].select do |v| - options.keys.include?(v.to_s) - end - - if options_include_groups.any? - ordered_groups = outdated_gems_by_groups.keys.compact.sort - [nil, ordered_groups].flatten.each do |groups| - gems = outdated_gems_by_groups[groups] - contains_group = if groups - groups.split(",").include?(options[:group]) - else - options[:group] == "group" - end - - next if (!options[:groups] && !contains_group) || gems.nil? - - unless options[:parseable] - if groups - Bundler.ui.info "===== Group #{groups} =====" - else - Bundler.ui.info "===== Without group =====" - end - end - - gems.each do |gem| - print_gem( - gem[:current_spec], - gem[:active_spec], - gem[:dependency], - groups, - options_include_groups.any? - ) - end - end - else - outdated_gems_list.each do |gem| - print_gem( - gem[:current_spec], - gem[:active_spec], - gem[:dependency], - gem[:groups], - options_include_groups.any? - ) - end - end - - exit 1 - end - end - - private - - def retrieve_active_spec(strict, definition, current_spec) - if strict - active_spec = definition.find_resolved_spec(current_spec) - else - active_specs = definition.find_indexed_specs(current_spec) - if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 - active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - active_spec = active_specs.last - end - - active_spec - end - - def display_nothing_outdated_message(filter_options_patch) - unless options[:parseable] - if filter_options_patch.any? - display = filter_options_patch.map do |o| - o.sub("filter-", "") - end.join(" or ") - - Bundler.ui.info "No #{display} updates to display.\n" - else - Bundler.ui.info "Bundle up to date!\n" - end - end - end - - def print_gem(current_spec, active_spec, dependency, groups, options_include_groups) - spec_version = "#{active_spec.version}#{active_spec.git_version}" - spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from - current_version = "#{current_spec.version}#{current_spec.git_version}" - - if dependency && dependency.specific? - dependency_version = %(, requested #{dependency.requirement}) - end - - spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ - "installed #{current_version}#{dependency_version})" - - output_message = if options[:parseable] - spec_outdated_info.to_s - elsif options_include_groups || !groups - " * #{spec_outdated_info}" - else - " * #{spec_outdated_info} in groups \"#{groups}\"" - end - - Bundler.ui.info output_message.rstrip - end - - def check_for_deployment_mode - 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 " \ - "deployment mode. Run `bundle outdated` elsewhere.\n" \ - "\nIf this is a development machine, remove the " \ - "#{Bundler.default_gemfile} freeze" \ - "\nby running `#{suggested_command}`." - end - - def update_present_via_semver_portions(current_spec, active_spec, options) - current_major = current_spec.version.segments.first - active_major = active_spec.version.segments.first - - update_present = false - update_present = active_major > current_major if options["filter-major"] - - if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major - current_minor = get_version_semver_portion_value(current_spec, 1) - active_minor = get_version_semver_portion_value(active_spec, 1) - - update_present = active_minor > current_minor if options["filter-minor"] - - if !update_present && options["filter-patch"] && current_minor == active_minor - current_patch = get_version_semver_portion_value(current_spec, 2) - active_patch = get_version_semver_portion_value(active_spec, 2) - - update_present = active_patch > current_patch - end - end - - update_present - end - - def get_version_semver_portion_value(spec, version_portion_index) - version_section = spec.version.segments[version_portion_index, 1] - version_section.nil? ? 0 : (version_section.first || 0) - end - end -end diff --git a/lib/bundler/cli/package.rb b/lib/bundler/cli/package.rb deleted file mode 100644 index 2dcd0e1e29..0000000000 --- a/lib/bundler/cli/package.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Package - attr_reader :options - - def initialize(options) - @options = options - end - - def run - Bundler.ui.level = "error" if options[:quiet] - Bundler.settings.set_command_option_if_given :path, options[:path] - Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"] - Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] - - setup_cache_all - install - - # TODO: move cache contents here now that all bundles are locked - custom_path = Bundler.settings[:path] if options[:path] - Bundler.load.cache(custom_path) - end - - private - - def install - require "bundler/cli/install" - options = self.options.dup - if Bundler.settings[:cache_all_platforms] - options["local"] = false - options["update"] = true - end - Bundler::CLI::Install.new(options).run - end - - def setup_cache_all - all = options.fetch(:all, Bundler.feature_flag.cache_command_is_package? || nil) - - 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 " \ - "to package them as well, please pass the --all flag. This will be the default " \ - "on Bundler 2.0." - end - end - end -end diff --git a/lib/bundler/cli/platform.rb b/lib/bundler/cli/platform.rb deleted file mode 100644 index e97cad49a4..0000000000 --- a/lib/bundler/cli/platform.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Platform - attr_reader :options - def initialize(options) - @options = options - end - - def run - platforms, ruby_version = Bundler.ui.silence do - locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version - gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string - [Bundler.definition.platforms.map {|p| "* #{p}" }, - locked_ruby_version || gemfile_ruby_version] - end - output = [] - - if options[:ruby] - if ruby_version - output << ruby_version - else - output << "No ruby version specified" - end - else - output << "Your platform is: #{RUBY_PLATFORM}" - output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" - - if ruby_version - output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" - - begin - Bundler.definition.validate_runtime! - output << "Your current platform satisfies the Ruby version requirement." - rescue RubyVersionMismatch => e - output << e.message - end - else - output << "Your Gemfile does not specify a Ruby version requirement." - end - end - - Bundler.ui.info output.join("\n\n") - end - end -end diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb deleted file mode 100644 index 5488a9f28d..0000000000 --- a/lib/bundler/cli/plugin.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_thor" -module Bundler - class CLI::Plugin < Thor - desc "install PLUGINS", "Install the plugin from the source" - long_desc <<-D - Install plugins either from the rubygems source provided (with --source option) or from a git source provided with (--git option). If no sources are provided, it uses Gem.sources - D - method_option "source", :type => :string, :default => nil, :banner => - "URL of the RubyGems source to fetch the plugin from" - method_option "version", :type => :string, :default => nil, :banner => - "The version of the plugin to fetch" - method_option "git", :type => :string, :default => nil, :banner => - "URL of the git repo to fetch from" - method_option "branch", :type => :string, :default => nil, :banner => - "The git branch to checkout" - method_option "ref", :type => :string, :default => nil, :banner => - "The git revision to check out" - def install(*plugins) - Bundler::Plugin.install(plugins, options) - end - end -end diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb deleted file mode 100644 index 9b9cdaa9b3..0000000000 --- a/lib/bundler/cli/pristine.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Pristine - def initialize(gems) - @gems = gems - end - - def run - CLI::Common.ensure_all_gems_in_lockfile!(@gems) - definition = Bundler.definition - definition.validate_runtime! - installer = Bundler::Installer.new(Bundler.root, definition) - - Bundler.load.specs.each do |spec| - 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.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY - - case source = spec.source - when Source::Rubygems - cached_gem = spec.cache_file - unless File.exist?(cached_gem) - Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") - next - end - - FileUtils.rm_rf spec.full_gem_path - when Source::Git - source.remote! - FileUtils.rm_rf spec.full_gem_path - else - Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") - next - end - - Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec - end - end - end -end diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb deleted file mode 100644 index 61756801b2..0000000000 --- a/lib/bundler/cli/show.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Show - attr_reader :options, :gem_name, :latest_specs - def initialize(options, gem_name) - @options = options - @gem_name = gem_name - @verbose = options[:verbose] || options[:outdated] - @latest_specs = fetch_latest_specs if @verbose - end - - def run - Bundler.ui.silence do - Bundler.definition.validate_runtime! - Bundler.load.lock - end - - if gem_name - if gem_name == "bundler" - path = File.expand_path("../../../..", __FILE__) - else - spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) - return unless spec - path = spec.full_gem_path - unless File.directory?(path) - Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at:" - end - end - return Bundler.ui.info(path) - end - - if options[:paths] - Bundler.load.specs.sort_by(&:name).map do |s| - Bundler.ui.info s.full_gem_path - end - else - Bundler.ui.info "Gems included by the bundle:" - Bundler.load.specs.sort_by(&:name).each do |s| - desc = " * #{s.name} (#{s.version}#{s.git_version})" - if @verbose - latest = latest_specs.find {|l| l.name == s.name } - Bundler.ui.info <<-END.gsub(/^ +/, "") - #{desc} - \tSummary: #{s.summary || "No description available."} - \tHomepage: #{s.homepage || "No website available."} - \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} - END - else - Bundler.ui.info desc - end - end - end - end - - private - - def fetch_latest_specs - definition = Bundler.definition(true) - if options[:outdated] - Bundler.ui.info "Fetching remote specs for outdated check...\n\n" - Bundler.ui.silence { definition.resolve_remotely! } - else - definition.resolve_with_cache! - end - Bundler.reset! - definition.specs - end - - def outdated?(current, latest) - return false unless latest - Gem::Version.new(current.version) < Gem::Version.new(latest.version) - end - end -end diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb deleted file mode 100644 index 3890ea307a..0000000000 --- a/lib/bundler/cli/update.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Update - attr_reader :options, :gems - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - Bundler.ui.level = "error" if options[:quiet] - - Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? - - sources = Array(options[:source]) - groups = Array(options[:group]).map(&:to_sym) - - 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 - Bundler.definition(true) - else - unless Bundler.default_lockfile.exist? - raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ - "Run `bundle install` to update and install the bundled gems." - end - Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) - - if groups.any? - specs = Bundler.definition.specs_for groups - gems.concat(specs.map(&:name)) - end - - Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], - :lock_shared_dependencies => options[:conservative], - :bundler => options[:bundler]) - end - - Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - opts = options.dup - opts["update"] = true - opts["local"] = options[:local] - - Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] - - Bundler.definition.validate_runtime! - installer = Installer.install Bundler.root, Bundler.definition, opts - Bundler.load.cache if Bundler.app_cache.exist? - - if CLI::Common.clean_after_install? - require "bundler/cli/clean" - Bundler::CLI::Clean.new(options).run - end - - if locked_gems = Bundler.definition.locked_gems - gems.each do |name| - locked_version = locked_gems.specs.find {|s| s.name == name } - locked_version &&= locked_version.version - next unless locked_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::CLI::Common.output_without_groups_message - Bundler::CLI::Common.output_post_install_messages installer.post_install_messages - end - end -end diff --git a/lib/bundler/cli/viz.rb b/lib/bundler/cli/viz.rb deleted file mode 100644 index 644f9b25cf..0000000000 --- a/lib/bundler/cli/viz.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Viz - attr_reader :options, :gem_name - def initialize(options) - @options = options - end - - def run - # make sure we get the right `graphviz`. There is also a `graphviz` - # gem we're not built to support - gem "ruby-graphviz" - require "graphviz" - - options[:without] = options[:without].join(":").tr(" ", ":").split(":") - output_file = File.expand_path(options[:file]) - - graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) - graph.viz - rescue LoadError => e - Bundler.ui.error e.inspect - Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" - Bundler.ui.warn "`gem install ruby-graphviz`" - rescue StandardError => e - raise unless e.message =~ /GraphViz not installed or dot not in PATH/ - Bundler.ui.error e.message - Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." - end - end -end diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb deleted file mode 100644 index 6c241ca07a..0000000000 --- a/lib/bundler/compact_index_client.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true - -require "pathname" -require "set" - -module Bundler - class CompactIndexClient - DEBUG_MUTEX = Mutex.new - def self.debug - return unless ENV["DEBUG_COMPACT_INDEX"] - DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } - end - - class Error < StandardError; end - - require "bundler/compact_index_client/cache" - require "bundler/compact_index_client/updater" - - attr_reader :directory - - # @return [Lambda] A lambda that takes an array of inputs and a block, and - # maps the inputs with the block in parallel. - # - attr_accessor :in_parallel - - def initialize(directory, fetcher) - @directory = Pathname.new(directory) - @updater = Updater.new(fetcher) - @cache = Cache.new(@directory) - @endpoints = Set.new - @info_checksums_by_name = {} - @parsed_checksums = false - @mutex = Mutex.new - @in_parallel = lambda do |inputs, &blk| - inputs.map(&blk) - end - end - - def names - Bundler::CompactIndexClient.debug { "/names" } - update(@cache.names_path, "names") - @cache.names - end - - def versions - Bundler::CompactIndexClient.debug { "/versions" } - update(@cache.versions_path, "versions") - versions, @info_checksums_by_name = @cache.versions - versions - end - - def dependencies(names) - Bundler::CompactIndexClient.debug { "dependencies(#{names})" } - in_parallel.call(names) do |name| - update_info(name) - @cache.dependencies(name).map {|d| d.unshift(name) } - end.flatten(1) - end - - def spec(name, version, platform = nil) - Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" } - update_info(name) - @cache.specific_dependency(name, version, platform) - end - - def update_and_parse_checksums! - Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } - return @info_checksums_by_name if @parsed_checksums - update(@cache.versions_path, "versions") - @info_checksums_by_name = @cache.checksums - @parsed_checksums = true - end - - private - - def update(local_path, remote_path) - Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } - unless synchronize { @endpoints.add?(remote_path) } - Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } - return - end - @updater.update(local_path, url(remote_path)) - end - - def update_info(name) - Bundler::CompactIndexClient.debug { "update_info(#{name})" } - path = @cache.info_path(name) - checksum = @updater.checksum_for_file(path) - unless existing = @info_checksums_by_name[name] - Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } - return - end - if checksum == existing - Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } - return - end - Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } - update(path, "info/#{name}") - end - - def url(path) - path - end - - def synchronize - @mutex.synchronize { yield } - end - end -end diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb deleted file mode 100644 index f6105d3bb3..0000000000 --- a/lib/bundler/compact_index_client/cache.rb +++ /dev/null @@ -1,118 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CompactIndexClient - class Cache - attr_reader :directory - - def initialize(directory) - @directory = Pathname.new(directory).expand_path - info_roots.each do |dir| - SharedHelpers.filesystem_access(dir) do - FileUtils.mkdir_p(dir) - end - end - end - - def names - lines(names_path) - end - - def names_path - directory.join("names") - end - - def versions - versions_by_name = Hash.new {|hash, key| hash[key] = [] } - info_checksums_by_name = {} - - lines(versions_path).each do |line| - name, versions_string, info_checksum = line.split(" ", 3) - info_checksums_by_name[name] = info_checksum || "" - versions_string.split(",").each do |version| - if version.start_with?("-") - version = version[1..-1].split("-", 2).unshift(name) - versions_by_name[name].delete(version) - else - version = version.split("-", 2).unshift(name) - versions_by_name[name] << version - end - end - end - - [versions_by_name, info_checksums_by_name] - end - - def versions_path - directory.join("versions") - end - - def checksums - checksums = {} - - lines(versions_path).each do |line| - name, _, checksum = line.split(" ", 3) - checksums[name] = checksum - end - - checksums - end - - def dependencies(name) - lines(info_path(name)).map do |line| - parse_gem(line) - end - end - - def info_path(name) - name = name.to_s - if name =~ /[^a-z0-9_-]/ - name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" - info_roots.last.join(name) - else - info_roots.first.join(name) - end - end - - def specific_dependency(name, version, platform) - pattern = [version, platform].compact.join("-") - return nil if pattern.empty? - - gem_lines = info_path(name).read - gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0] - gem_line ? parse_gem(gem_line) : nil - end - - private - - def lines(path) - return [] unless path.file? - lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") - header = lines.index("---") - header ? lines[header + 1..-1] : lines - end - - def parse_gem(string) - version_and_platform, rest = string.split(" ", 2) - version, platform = version_and_platform.split("-", 2) - dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest - dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : [] - requirements = requirements ? requirements.map {|r| parse_dependency(r) } : [] - [version, platform, dependencies, requirements] - end - - def parse_dependency(string) - dependency = string.split(":") - dependency[-1] = dependency[-1].split("&") if dependency.size > 1 - dependency - end - - def info_roots - [ - directory.join("info"), - directory.join("info-special-characters"), - ] - end - end - end -end diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb deleted file mode 100644 index 3a4e4441ca..0000000000 --- a/lib/bundler/compact_index_client/updater.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_fileutils" -require "stringio" -require "zlib" - -module Bundler - class CompactIndexClient - class Updater - class MisMatchedChecksumError < Error - def initialize(path, server_checksum, local_checksum) - @path = path - @server_checksum = server_checksum - @local_checksum = local_checksum - end - - def message - "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \ - "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})." - end - end - - def initialize(fetcher) - @fetcher = fetcher - require "tmpdir" - end - - def update(local_path, remote_path, retrying = nil) - headers = {} - - Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| - local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename) - - # first try to fetch any new bytes on the existing file - if retrying.nil? && local_path.file? - FileUtils.cp local_path, local_temp_path - headers["If-None-Match"] = etag_for(local_temp_path) - headers["Range"] = - if local_temp_path.size.nonzero? - # Subtract a byte to ensure the range won't be empty. - # Avoids 416 (Range Not Satisfiable) responses. - "bytes=#{local_temp_path.size - 1}-" - else - "bytes=#{local_temp_path.size}-" - end - else - # Fastly ignores Range when Accept-Encoding: gzip is set - headers["Accept-Encoding"] = "gzip" - end - - response = @fetcher.call(remote_path, headers) - return nil if response.is_a?(Net::HTTPNotModified) - - content = response.body - if response["Content-Encoding"] == "gzip" - content = Zlib::GzipReader.new(StringIO.new(content)).read - end - - SharedHelpers.filesystem_access(local_temp_path) do - if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? - local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } - else - local_temp_path.open("w") {|f| f << content } - end - end - - response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "") - if etag_for(local_temp_path) == response_etag - SharedHelpers.filesystem_access(local_path) do - FileUtils.mv(local_temp_path, local_path) - end - return nil - end - - if retrying - raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path)) - end - - update(local_path, remote_path, :retrying) - end - end - - def etag_for(path) - sum = checksum_for_file(path) - sum ? %("#{sum}") : nil - end - - def slice_body(body, range) - if body.respond_to?(:byteslice) - body.byteslice(range) - else # pre-1.9.3 - body.unpack("@#{range.first}a#{range.end + 1}").first - end - end - - def checksum_for_file(path) - return nil unless path.file? - # This must use IO.read instead of Digest.file().hexdigest - # because we need to preserve \n line endings on windows when calculating - # the checksum - SharedHelpers.filesystem_access(path, :read) do - SharedHelpers.digest(:MD5).hexdigest(IO.read(path)) - end - end - end - end -end diff --git a/lib/bundler/compatibility_guard.rb b/lib/bundler/compatibility_guard.rb deleted file mode 100644 index 750a1db04f..0000000000 --- a/lib/bundler/compatibility_guard.rb +++ /dev/null @@ -1,14 +0,0 @@ -# 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 diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb deleted file mode 100644 index 2e4ebb37ee..0000000000 --- a/lib/bundler/constants.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Bundler - WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ - FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ - NULL = WINDOWS ? "NUL" : "/dev/null" -end diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb deleted file mode 100644 index 31532d108d..0000000000 --- a/lib/bundler/current_ruby.rb +++ /dev/null @@ -1,86 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # Returns current version of Ruby - # - # @return [CurrentRuby] Current version of Ruby - def self.current_ruby - @current_ruby ||= CurrentRuby.new - end - - class CurrentRuby - KNOWN_MINOR_VERSIONS = %w[ - 1.8 - 1.9 - 2.0 - 2.1 - 2.2 - 2.3 - 2.4 - 2.5 - ].freeze - - KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze - - KNOWN_PLATFORMS = %w[ - jruby - maglev - mingw - mri - mswin - mswin64 - rbx - ruby - x64_mingw - ].freeze - - def ruby? - !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev") - end - - def mri? - !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby") - end - - def rbx? - ruby? && defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx" - end - - def jruby? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" - end - - def maglev? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "maglev" - end - - def mswin? - Bundler::WINDOWS - end - - def mswin64? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" - end - - def mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" - end - - def x64_mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" - end - - (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| - trimmed_version = version.tr(".", "") - define_method(:"on_#{trimmed_version}?") do - RUBY_VERSION.start_with?("#{version}.") - end - - KNOWN_PLATFORMS.each do |platform| - define_method(:"#{platform}_#{trimmed_version}?") do - send(:"#{platform}?") && send(:"on_#{trimmed_version}?") - end - end - end - end -end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb deleted file mode 100644 index ad16389dae..0000000000 --- a/lib/bundler/definition.rb +++ /dev/null @@ -1,984 +0,0 @@ -# frozen_string_literal: true - -require "bundler/lockfile_parser" -require "set" - -module Bundler - class Definition - include GemHelpers - - attr_reader( - :dependencies, - :gem_version_promoter, - :locked_deps, - :locked_gems, - :platforms, - :requires, - :ruby_version, - :lockfile, - :gemfiles - ) - - # Given a gemfile and lockfile creates a Bundler definition - # - # @param gemfile [Pathname] Path to Gemfile - # @param lockfile [Pathname,nil] Path to Gemfile.lock - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @return [Bundler::Definition] - def self.build(gemfile, lockfile, unlock) - unlock ||= {} - gemfile = Pathname.new(gemfile).expand_path - - raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? - - Dsl.evaluate(gemfile, lockfile, unlock) - end - - # - # How does the new system work? - # - # * Load information from Gemfile and Lockfile - # * Invalidate stale locked specs - # * All specs from stale source are stale - # * All specs that are reachable only through a stale - # dependency are stale. - # * If all fresh dependencies are satisfied by the locked - # specs, then we can try to resolve locally. - # - # @param lockfile [Pathname] Path to Gemfile.lock - # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile - # @param sources [Bundler::SourceList] - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version - # @param optional_groups [Array(String)] A list of optional groups - def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) - 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 - @sources = sources - @unlock = unlock - @optional_groups = optional_groups - @remote = false - @specs = nil - @ruby_version = ruby_version - @gemfiles = gemfiles - - @lockfile = lockfile - @lockfile_contents = String.new - @locked_bundler_version = nil - @locked_ruby_version = nil - - if lockfile && File.exist?(lockfile) - @lockfile_contents = Bundler.read_file(lockfile) - @locked_gems = LockfileParser.new(@lockfile_contents) - @locked_platforms = @locked_gems.platforms - @platforms = @locked_platforms.dup - @locked_bundler_version = @locked_gems.bundler_version - @locked_ruby_version = @locked_gems.ruby_version - - if unlock != true - @locked_deps = @locked_gems.dependencies - @locked_specs = SpecSet.new(@locked_gems.specs) - @locked_sources = @locked_gems.sources - else - @unlock = {} - @locked_deps = {} - @locked_specs = SpecSet.new([]) - @locked_sources = [] - end - else - @unlock = {} - @platforms = [] - @locked_gems = nil - @locked_deps = {} - @locked_specs = SpecSet.new([]) - @locked_sources = [] - @locked_platforms = [] - end - - @unlock[:gems] ||= [] - @unlock[:sources] ||= [] - @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object - @ruby_version.diff(locked_ruby_version_object) - end - @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) - - add_current_platform unless Bundler.frozen? - - converge_path_sources_to_gemspec_sources - @path_changes = converge_paths - @source_changes = converge_sources - - unless @unlock[:lock_shared_dependencies] - eager_unlock = expand_dependencies(@unlock[:gems]) - @unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name) - end - - @gem_version_promoter = create_gem_version_promoter - - @dependency_changes = converge_dependencies - @local_changes = converge_locals - - @requires = compute_requires - end - - def create_gem_version_promoter - locked_specs = - if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? - # Definition uses an empty set of locked_specs to indicate all gems - # are unlocked, but GemVersionPromoter needs the locked_specs - # for conservative comparison. - Bundler::SpecSet.new(@locked_gems.specs) - else - @locked_specs - end - GemVersionPromoter.new(locked_specs, @unlock[:gems]) - end - - def resolve_with_cache! - raise "Specs already loaded" if @specs - sources.cached! - specs - end - - def resolve_remotely! - raise "Specs already loaded" if @specs - @remote = true - sources.remote! - specs - end - - # For given dependency list returns a SpecSet with Gemspec of all the required - # dependencies. - # 1. The method first resolves the dependencies specified in Gemfile - # 2. After that it tries and fetches gemspec of resolved dependencies - # - # @return [Bundler::SpecSet] - def specs - @specs ||= begin - begin - specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies) - rescue GemNotFound => e # Handle yanked gem - gem_name, gem_version = extract_gem_info(e) - locked_gem = @locked_specs[gem_name].last - raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote - raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \ - "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \ - "that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \ - "to a different version of #{locked_gem} that hasn't been removed in order to install." - end - unless specs["bundler"].any? - bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler - end - - specs - end - end - - def new_specs - specs - @locked_specs - end - - def removed_specs - @locked_specs - specs - end - - def new_platform? - @new_platform - end - - def missing_specs - missing = [] - resolve.materialize(requested_dependencies, missing) - missing - end - - def missing_specs? - missing = missing_specs - return false if missing.empty? - 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 - - def requested_specs - @requested_specs ||= begin - groups = requested_groups - groups.map!(&:to_sym) - specs_for(groups) - end - end - - def current_dependencies - dependencies.select(&:should_include?) - end - - def specs_for(groups) - deps = dependencies.select {|d| (d.groups & groups).any? } - deps.delete_if {|d| !d.should_include? } - specs.for(expand_dependencies(deps)) - end - - # Resolve all the dependencies specified in Gemfile. It ensures that - # dependencies that have been already resolved via locked file and are fresh - # are reused when resolving dependencies - # - # @return [SpecSet] resolved dependencies - def resolve - @resolve ||= begin - last_resolve = converge_locked_specs - 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") - last_resolve - else - # Run a resolve against the locally available gems - Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") - last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) - end - end - end - - def index - @index ||= Index.build do |idx| - dependency_names = @dependencies.map(&:name) - - sources.all_sources.each do |source| - source.dependency_names = dependency_names - pinned_spec_names(source) - idx.add_source source.specs - dependency_names.concat(source.unmet_deps).uniq! - end - - double_check_for_index(idx, dependency_names) - end - end - - # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both - # sources A and B. At this point, the API request will have found all the versions of Bar in source A, - # but will not have found any versions of Bar from source B, which is a problem if the requested version - # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for - # each spec we found, we add all possible versions from all sources to the index. - def double_check_for_index(idx, dependency_names) - pinned_names = pinned_spec_names - loop do - idxcount = idx.size - - names = :names # do this so we only have to traverse to get dependency_names from the index once - unmet_dependency_names = lambda do - return names unless names == :names - new_names = sources.all_sources.map(&:dependency_names_to_double_check) - return names = nil if new_names.compact! - names = new_names.flatten(1).concat(dependency_names) - names.uniq! - names -= pinned_names - names - end - - sources.all_sources.each do |source| - source.double_check_for(unmet_dependency_names) - end - - break if idxcount == idx.size - end - end - private :double_check_for_index - - def has_rubygems_remotes? - sources.rubygems_sources.any? {|s| s.remotes.any? } - end - - def has_local_dependencies? - !sources.path_sources.empty? || !sources.git_sources.empty? - end - - def spec_git_paths - sources.git_sources.map {|s| s.path.to_s } - end - - def groups - dependencies.map(&:groups).flatten.uniq - end - - def lock(file, preserve_unknown_sections = false) - contents = to_lock - - # Convert to \r\n if the existing lock has them - # i.e., Windows with `git config core.autocrlf=true` - contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n") - - if @locked_bundler_version - locked_major = @locked_bundler_version.segments.first - current_major = Gem::Version.create(Bundler::VERSION).segments.first - - if updating_major = locked_major < current_major - Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \ - "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}." - end - end - - preserve_unknown_sections ||= !updating_major && (Bundler.frozen? || !(unlocking? || @unlocking_bundler)) - return if lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) - - if Bundler.frozen? - Bundler.ui.error "Cannot write a changed lockfile while frozen." - return - end - - SharedHelpers.filesystem_access(file) do |p| - File.open(p, "wb") {|f| f.puts(contents) } - end - end - - def locked_bundler_version - if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION) - new_version = Bundler::VERSION - end - - new_version || @locked_bundler_version || Bundler::VERSION - end - - def locked_ruby_version - return unless ruby_version - if @unlock[:ruby] || !@locked_ruby_version - Bundler::RubyVersion.system - else - @locked_ruby_version - end - end - - def locked_ruby_version_object - return unless @locked_ruby_version - @locked_ruby_version_object ||= begin - unless version = RubyVersion.from_string(@locked_ruby_version) - raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ - "#{@lockfile} could not be parsed. " \ - "Try running bundle update --ruby to resolve this." - end - version - end - end - - def to_lock - require "bundler/lockfile_generator" - LockfileGenerator.generate(self) - end - - def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) - msg = String.new - msg << "You are trying to install in deployment mode after changing\n" \ - "your Gemfile. Run `bundle install` elsewhere and add the\n" \ - "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." - - unless explicit_flag - 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 - msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ - "freeze \nby running `#{suggested_command}`." - end - - added = [] - deleted = [] - changed = [] - - new_platforms = @platforms - @locked_platforms - deleted_platforms = @locked_platforms - @platforms - added.concat new_platforms.map {|p| "* platform: #{p}" } - deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } - - gemfile_sources = sources.lock_sources - - new_sources = gemfile_sources - @locked_sources - deleted_sources = @locked_sources - gemfile_sources - - new_deps = @dependencies - @locked_deps.values - deleted_deps = @locked_deps.values - @dependencies - - # 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?) - new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } - deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } - end - - if @locked_sources != gemfile_sources - if new_sources.any? - added.concat new_sources.map {|source| "* source: #{source}" } - end - - if deleted_sources.any? - deleted.concat deleted_sources.map {|source| "* source: #{source}" } - end - end - - added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? - if deleted_deps.any? - deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } - end - - both_sources = Hash.new {|h, k| h[k] = [] } - @dependencies.each {|d| both_sources[d.name][0] = d } - @locked_deps.each {|name, d| both_sources[name][1] = d.source } - - both_sources.each do |name, (dep, lock_source)| - next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep)) - gemfile_source_name = (dep && dep.source) || "no specified source" - lockfile_source_name = lock_source || "no specified source" - changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" - end - - reason = change_reason - msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty? - msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? - msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? - msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? - msg << "\n" - - raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? - end - - def validate_runtime! - validate_ruby! - validate_platforms! - end - - def validate_ruby! - return unless ruby_version - - if diff = ruby_version.diff(Bundler::RubyVersion.system) - problem, expected, actual = diff - - msg = case problem - when :engine - "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" - when :version - "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" - when :engine_version - "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" - when :patchlevel - if !expected.is_a?(String) - "The Ruby patchlevel in your Gemfile must be a string" - else - "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" - end - end - - raise RubyVersionMismatch, msg - end - end - - def validate_platforms! - return if @platforms.any? do |bundle_platform| - Bundler.rubygems.platforms.any? do |local_platform| - MatchPlatform.platforms_match?(bundle_platform, local_platform) - end - end - - raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ - "but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \ - "there's no compatible match between those two lists." - end - - def add_platform(platform) - @new_platform ||= !@platforms.include?(platform) - @platforms |= [platform] - end - - def remove_platform(platform) - return if @platforms.delete(Gem::Platform.new(platform)) - raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" - end - - def add_current_platform - current_platform = Bundler.local_platform - add_platform(current_platform) if Bundler.feature_flag.specific_platform? - add_platform(generic(current_platform)) - end - - def find_resolved_spec(current_spec) - specs.find_by_name_and_platform(current_spec.name, current_spec.platform) - end - - def find_indexed_specs(current_spec) - index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) - end - - attr_reader :sources - private :sources - - def nothing_changed? - !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes - end - - def unlocking? - @unlocking - end - - private - - def change_reason - if unlocking? - unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| - if v == true - k.to_s - else - v = Array(v) - "#{k}: (#{v.join(", ")})" - end - end.join(", ") - return "bundler is unlocking #{unlock_reason}" - end - [ - [@source_changes, "the list of sources changed"], - [@dependency_changes, "the dependencies in your gemfile changed"], - [@new_platform, "you added a new platform to your gemfile"], - [@path_changes, "the gemspecs for path gems changed"], - [@local_changes, "the gemspecs for git local gems changed"], - ].select(&:first).map(&:last).join(", ") - end - - def pretty_dep(dep, source = false) - SharedHelpers.pretty_dependency(dep, source) - end - - # Check if the specs of the given source changed - # according to the locked source. - def specs_changed?(source) - locked = @locked_sources.find {|s| s == source } - - !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) - end - - def dependencies_for_source_changed?(source, locked_source = source) - deps_for_source = @dependencies.select {|s| s.source == source } - locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } - - Set.new(deps_for_source) != Set.new(locked_deps_for_source) - end - - def specs_for_source_changed?(source) - locked_index = Index.new - locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) - - # order here matters, since Index#== is checking source.specs.include?(locked_index) - 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 - - # Get all locals and override their matching sources. - # Return true if any of the locals changed (for example, - # they point to a new revision) or depend on new specs. - def converge_locals - locals = [] - - Bundler.settings.local_overrides.map do |k, v| - spec = @dependencies.find {|s| s.name == k } - source = spec && spec.source - if source && source.respond_to?(:local_override!) - source.unlock! if @unlock[:gems].include?(spec.name) - locals << [source, source.local_override!(v)] - end - end - - sources_with_changes = locals.select do |source, changed| - changed || specs_changed?(source) - end.map(&:first) - !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? - end - - def converge_paths - sources.path_sources.any? do |source| - specs_changed?(source) - end - end - - def converge_path_source_to_gemspec_source(source) - return source unless source.instance_of?(Source::Path) - gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source } - gemspec_source || source - end - - def converge_path_sources_to_gemspec_sources - @locked_sources.map! do |source| - converge_path_source_to_gemspec_source(source) - end - @locked_specs.each do |spec| - spec.source &&= converge_path_source_to_gemspec_source(spec.source) - end - @locked_deps.each do |_, dep| - dep.source &&= converge_path_source_to_gemspec_source(dep.source) - end - end - - def converge_rubygems_sources - return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - - changes = false - - # Get the RubyGems sources from the Gemfile.lock - locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - # Get the RubyGems remotes from the Gemfile - actual_remotes = sources.rubygems_remotes - - # If there is a RubyGems source in both - if !locked_gem_sources.empty? && !actual_remotes.empty? - locked_gem_sources.each do |locked_gem| - # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) - end - 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, - # 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. - changes |= sources.replace_sources!(@locked_sources) - - sources.all_sources.each do |source| - # If the source is unlockable and the current command allows an unlock of - # the source (for example, you are doing a `bundle update <foo>` of a git-pinned - # gem), unlock it. For git sources, this means to unlock the revision, which - # will cause the `ref` used to be the most recent for the branch (or master) if - # an explicit `ref` is not used. - if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) - source.unlock! - changes = true - end - end - - changes - end - - def converge_dependencies - frozen = Bundler.frozen? - (@dependencies + @locked_deps.values).each do |dep| - locked_source = @locked_deps[dep.name] - # This is to make sure that if bundler is installing in deployment mode and - # after locked_source and sources don't match, we still use locked_source. - if frozen && !locked_source.nil? && - locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist? - dep.source = locked_source.source - elsif dep.source - dep.source = sources.get(dep.source) - end - if dep.source.is_a?(Source::Gemspec) - dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq! - end - end - - changes = false - # We want to know if all match, but don't want to check all entries - # This means we need to return false if any dependency doesn't match - # the lock or doesn't exist in the lock. - @dependencies.each do |dependency| - unless locked_dep = @locked_deps[dependency.name] - changes = true - next - end - - # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile - # doesn't carry a notion of the dependency type, if you use - # add_development_dependency in a gemspec that's loaded with the gemspec - # directive, the lockfile dependencies and resolved dependencies end up - # with a mismatch on #type. Work around that by setting the type on the - # dep from the lockfile. - locked_dep.instance_variable_set(:@type, dependency.type) - - # We already know the name matches from the hash lookup - # so we only need to check the requirement now - changes ||= dependency.requirement != locked_dep.requirement - end - - changes - end - - # Remove elements from the locked specs that are expired. This will most - # commonly happen if the Gemfile has changed since the lockfile was last - # generated - def converge_locked_specs - deps = [] - - # Build a list of dependencies that are the same in the Gemfile - # and Gemfile.lock. If the Gemfile modified a dependency, but - # the gem in the Gemfile.lock still satisfies it, this is fine - # too. - @dependencies.each do |dep| - locked_dep = @locked_deps[dep.name] - - # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep - locked_dep = nil unless locked_dep == dep - - if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep) - deps << dep - elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source) - @locked_specs.each do |s| - @unlock[:gems] << s.name if s.source == dep.source - end - - dep.source.unlock! if dep.source.respond_to?(:unlock!) - dep.source.specs.each {|s| @unlock[:gems] << s.name } - end - end - - unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec? - - converged = [] - @locked_specs.each do |s| - # Replace the locked dependency's source with the equivalent source from the Gemfile - dep = @dependencies.find {|d| s.satisfies?(d) } - s.source = (dep && dep.source) || sources.get(s.source) - - # Don't add a spec to the list if its source is expired. For example, - # if you change a Git gem to RubyGems. - next if s.source.nil? - next if @unlock[:sources].include?(s.source.name) - - # XXX This is a backwards-compatibility fix to preserve the ability to - # unlock a single gem by passing its name via `--source`. See issue #3759 - # TODO: delete in Bundler 2 - next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name) - - # If the spec is from a path source and it doesn't exist anymore - # then we unlock it. - - # Path sources have special logic - if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) - 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 - # commonly happens if the version changed in the gemspec - next unless other - - deps2 = other.dependencies.select {|d| d.type != :development } - runtime_dependencies = s.dependencies.select {|d| d.type != :development } - # If the dependencies of the path source have changed, unlock it - next unless runtime_dependencies.sort == deps2.sort - end - - converged << s - end - - resolve = SpecSet.new(converged) - resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems], false, false, false) - diff = nil - - # Now, we unlock any sources that do not have anymore gems pinned to it - sources.all_sources.each do |source| - next unless source.respond_to?(:unlock!) - - unless resolve.any? {|s| s.source == source } - diff ||= @locked_specs.to_a - resolve.to_a - source.unlock! if diff.any? {|s| s.source == source } - end - end - - resolve - end - - def in_locked_deps?(dep, locked_dep) - # Because the lockfile can't link a dep to a specific remote, we need to - # treat sources as equivalent anytime the locked dep has all the remotes - # that the Gemfile dep does. - locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source) - end - - def satisfies_locked_spec?(dep) - @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } - end - - # This list of dependencies is only used in #resolve, so it's OK to add - # the metadata dependencies here - def expanded_dependencies - @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) - if ruby_versions.empty? || !@ruby_version.exact? - concat_ruby_version_requirements(RubyVersion.system) - concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby] - end - [ - Dependency.new("ruby\0", ruby_versions), - Dependency.new("rubygems\0", Gem::VERSION), - ] - end - end - - def concat_ruby_version_requirements(ruby_version, ruby_versions = []) - return ruby_versions unless ruby_version - if ruby_version.patchlevel - ruby_versions << ruby_version.to_gem_version_with_patchlevel - else - ruby_versions.concat(ruby_version.versions.map do |version| - requirement = Gem::Requirement.new(version) - if requirement.exact? - "~> #{version}.0" - else - requirement - end - end) - end - end - - def expand_dependencies(dependencies, remote = false) - sorted_platforms = Resolver.sort_platforms(@platforms) - deps = [] - dependencies.each do |dep| - dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) - next if !remote && !dep.current_platform? - platforms = dep.gem_platforms(sorted_platforms) - if platforms.empty? - mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] } - Bundler.ui.warn \ - "The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \ - "Bundler is installing for #{@platforms.join ", "} but the dependency " \ - "is only for #{mapped_platforms.join ", "}. " \ - "To add those platforms to the bundle, " \ - "run `bundle lock --add-platform #{mapped_platforms.join " "}`." - end - platforms.each do |p| - deps << DepProxy.new(dep, p) if remote || p == generic_local_platform - end - end - deps - end - - def requested_dependencies - groups = requested_groups - groups.map!(&:to_sym) - dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? } - end - - def source_requirements - # Load all specs from remote sources - index - - # Record the specs available in each gem's source, so that those - # specs will be available later when the resolver knows where to - # look for that gemspec (or its dependencies) - default = sources.default_source - source_requirements = { :default => default } - default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - dependencies.each do |dep| - next unless source = dep.source || default - source_requirements[dep.name] = source - 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 - end - - def pinned_spec_names(skip = nil) - pinned_names = [] - default = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && sources.default_source - @dependencies.each do |dep| - next unless dep_source = dep.source || default - next if dep_source == skip - pinned_names << dep.name - end - pinned_names - end - - def requested_groups - groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] - end - - def lockfiles_equal?(current, proposed, preserve_unknown_sections) - if preserve_unknown_sections - sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) - sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) - sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS - pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ - whitespace_cleanup = /\n{2,}/ - current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip - proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip - end - current == proposed - end - - def extract_gem_info(error) - # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources" - # to an array. The first element will be the gem name (e.g. foo), the second will be the version number. - error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten - end - - def compute_requires - dependencies.reduce({}) do |requires, dep| - next requires unless dep.should_include? - requires[dep.name] = Array(dep.autorequire || dep.name).map do |file| - # Allow `require: true` as an alias for `require: <name>` - file == true ? dep.name : file - end - requires - end - end - - def additional_base_requirements_for_resolve - 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| - name = locked_spec.name - 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 - end.values - 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 diff --git a/lib/bundler/dep_proxy.rb b/lib/bundler/dep_proxy.rb deleted file mode 100644 index 7a9423b14a..0000000000 --- a/lib/bundler/dep_proxy.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class DepProxy - attr_reader :__platform, :dep - - def initialize(dep, platform) - @dep = dep - @__platform = platform - end - - def hash - @hash ||= dep.hash - end - - def ==(other) - return if other.nil? - dep == other.dep && __platform == other.__platform - end - - alias_method :eql?, :== - - def type - @dep.type - end - - def name - @dep.name - end - - def requirement - @dep.requirement - end - - def to_s - s = name.dup - s << " (#{requirement})" unless requirement == Gem::Requirement.default - s << " #{__platform}" unless __platform == Gem::Platform::RUBY - s - end - - private - - def method_missing(*args, &blk) - @dep.send(*args, &blk) - end - end -end diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb deleted file mode 100644 index 24257bc113..0000000000 --- a/lib/bundler/dependency.rb +++ /dev/null @@ -1,138 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/dependency" -require "bundler/shared_helpers" -require "bundler/rubygems_ext" - -module Bundler - class Dependency < Gem::Dependency - attr_reader :autorequire - attr_reader :groups - attr_reader :platforms - - PLATFORM_MAP = { - :ruby => Gem::Platform::RUBY, - :ruby_18 => Gem::Platform::RUBY, - :ruby_19 => Gem::Platform::RUBY, - :ruby_20 => Gem::Platform::RUBY, - :ruby_21 => Gem::Platform::RUBY, - :ruby_22 => Gem::Platform::RUBY, - :ruby_23 => Gem::Platform::RUBY, - :ruby_24 => Gem::Platform::RUBY, - :ruby_25 => Gem::Platform::RUBY, - :mri => Gem::Platform::RUBY, - :mri_18 => Gem::Platform::RUBY, - :mri_19 => Gem::Platform::RUBY, - :mri_20 => Gem::Platform::RUBY, - :mri_21 => Gem::Platform::RUBY, - :mri_22 => Gem::Platform::RUBY, - :mri_23 => Gem::Platform::RUBY, - :mri_24 => Gem::Platform::RUBY, - :mri_25 => Gem::Platform::RUBY, - :rbx => Gem::Platform::RUBY, - :jruby => Gem::Platform::JAVA, - :jruby_18 => Gem::Platform::JAVA, - :jruby_19 => Gem::Platform::JAVA, - :mswin => Gem::Platform::MSWIN, - :mswin_18 => Gem::Platform::MSWIN, - :mswin_19 => Gem::Platform::MSWIN, - :mswin_20 => Gem::Platform::MSWIN, - :mswin_21 => Gem::Platform::MSWIN, - :mswin_22 => Gem::Platform::MSWIN, - :mswin_23 => Gem::Platform::MSWIN, - :mswin_24 => Gem::Platform::MSWIN, - :mswin_25 => Gem::Platform::MSWIN, - :mswin64 => Gem::Platform::MSWIN64, - :mswin64_19 => Gem::Platform::MSWIN64, - :mswin64_20 => Gem::Platform::MSWIN64, - :mswin64_21 => Gem::Platform::MSWIN64, - :mswin64_22 => Gem::Platform::MSWIN64, - :mswin64_23 => Gem::Platform::MSWIN64, - :mswin64_24 => Gem::Platform::MSWIN64, - :mswin64_25 => Gem::Platform::MSWIN64, - :mingw => Gem::Platform::MINGW, - :mingw_18 => Gem::Platform::MINGW, - :mingw_19 => Gem::Platform::MINGW, - :mingw_20 => Gem::Platform::MINGW, - :mingw_21 => Gem::Platform::MINGW, - :mingw_22 => Gem::Platform::MINGW, - :mingw_23 => Gem::Platform::MINGW, - :mingw_24 => Gem::Platform::MINGW, - :mingw_25 => Gem::Platform::MINGW, - :x64_mingw => Gem::Platform::X64_MINGW, - :x64_mingw_20 => Gem::Platform::X64_MINGW, - :x64_mingw_21 => Gem::Platform::X64_MINGW, - :x64_mingw_22 => Gem::Platform::X64_MINGW, - :x64_mingw_23 => Gem::Platform::X64_MINGW, - :x64_mingw_24 => Gem::Platform::X64_MINGW, - :x64_mingw_25 => Gem::Platform::X64_MINGW, - }.freeze - - REVERSE_PLATFORM_MAP = {}.tap do |reverse_platform_map| - PLATFORM_MAP.each do |key, value| - reverse_platform_map[value] ||= [] - reverse_platform_map[value] << key - end - - reverse_platform_map.each {|_, platforms| platforms.freeze } - end.freeze - - def initialize(name, version, options = {}, &blk) - type = options["type"] || :runtime - super(name, version, type) - - @autorequire = nil - @groups = Array(options["group"] || :default).map(&:to_sym) - @source = options["source"] - @platforms = Array(options["platforms"]) - @env = options["env"] - @should_include = options.fetch("should_include", true) - - @autorequire = Array(options["require"] || []) if options.key?("require") - 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) - return valid_platforms if @platforms.empty? - - @gem_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.uniq - - valid_platforms & @gem_platforms - end - - def should_include? - @should_include && current_env? && current_platform? - end - - def current_env? - return true unless @env - if @env.is_a?(Hash) - @env.all? do |key, val| - ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) - end - else - ENV[@env.to_s] - end - end - - def current_platform? - return true if @platforms.empty? - @platforms.any? do |p| - Bundler.current_ruby.send("#{p}?") - end - end - - def to_lock - out = super - out << "!" if source - out << "\n" - end - - def specific? - super - rescue NoMethodError - requirement != ">= 0" - end - end -end diff --git a/lib/bundler/deployment.rb b/lib/bundler/deployment.rb deleted file mode 100644 index 291e158ca0..0000000000 --- a/lib/bundler/deployment.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require "bundler/shared_helpers" -Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \ - "Capistrano, but Capistrano provides its own integration with " \ - "Bundler via the capistrano-bundler gem. Use it instead." - -module Bundler - class Deployment - def self.define_task(context, task_method = :task, opts = {}) - if defined?(Capistrano) && context.is_a?(Capistrano::Configuration) - context_name = "capistrano" - role_default = "{:except => {:no_release => true}}" - error_type = ::Capistrano::CommandError - else - context_name = "vlad" - role_default = "[:app]" - error_type = ::Rake::CommandFailedError - end - - roles = context.fetch(:bundle_roles, false) - opts[:roles] = roles if roles - - context.send :namespace, :bundle do - send :desc, <<-DESC - Install the current Bundler environment. By default, gems will be \ - installed to the shared/bundle path. Gems in the development and \ - test group will not be installed. The install command is executed \ - with the --deployment and --quiet flags. If the bundle cmd cannot \ - be found then you can override the bundle_cmd variable to specify \ - which one it should use. The base path to the app is fetched from \ - the :latest_release variable. Set it for custom deploy layouts. - - You can override any of these defaults by setting the variables shown below. - - N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ - in your deploy.rb file. - - set :bundle_gemfile, "Gemfile" - set :bundle_dir, File.join(fetch(:shared_path), 'bundle') - set :bundle_flags, "--deployment --quiet" - set :bundle_without, [:development, :test] - set :bundle_with, [:mysql] - set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" - set :bundle_roles, #{role_default} # e.g. [:app, :batch] - DESC - send task_method, :install, opts do - bundle_cmd = context.fetch(:bundle_cmd, "bundle") - bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") - bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle")) - bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") - bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact - bundle_with = [*context.fetch(:bundle_with, [])].compact - app_path = context.fetch(:latest_release) - if app_path.to_s.empty? - raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.") - end - args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"] - args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? - args << bundle_flags.to_s - args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? - args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty? - - run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}" - end - end - end - end -end diff --git a/lib/bundler/deprecate.rb b/lib/bundler/deprecate.rb deleted file mode 100644 index 387f632a39..0000000000 --- a/lib/bundler/deprecate.rb +++ /dev/null @@ -1,43 +0,0 @@ -# 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 - if defined? Bundler::Deprecate - # nothing to do! - elsif defined? ::Deprecate - Deprecate = ::Deprecate - elsif defined? Gem::Deprecate - Deprecate = Gem::Deprecate - else - class Deprecate - end - end - - unless Deprecate.respond_to?(:skip_during) - def Deprecate.skip_during - original = skip - self.skip = true - yield - ensure - self.skip = original - end - end - - unless Deprecate.respond_to?(:skip) - def Deprecate.skip - @skip ||= false - end - end - - unless Deprecate.respond_to?(:skip=) - def Deprecate.skip=(skip) - @skip = skip - end - end -end diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb deleted file mode 100644 index 8681163277..0000000000 --- a/lib/bundler/dsl.rb +++ /dev/null @@ -1,599 +0,0 @@ -# frozen_string_literal: true - -require "bundler/dependency" -require "bundler/ruby_dsl" - -module Bundler - class Dsl - include RubyDsl - - def self.evaluate(gemfile, lockfile, unlock) - builder = new - builder.eval_gemfile(gemfile) - builder.to_definition(lockfile, unlock) - end - - 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_accessor :dependencies - - def initialize - @source = nil - @sources = SourceList.new - @git_sources = {} - @dependencies = [] - @groups = [] - @install_conditionals = [] - @optional_groups = [] - @platforms = [] - @env = nil - @ruby_version = nil - @gemspecs = [] - @gemfile = nil - @gemfiles = [] - add_git_sources - end - - def eval_gemfile(gemfile, contents = nil) - expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent) - original_gemfile = @gemfile - @gemfile = expanded_gemfile_path - @gemfiles << expanded_gemfile_path - contents ||= Bundler.read_file(@gemfile.to_s) - instance_eval(contents.dup.untaint, gemfile.to_s, 1) - rescue Exception => e - message = "There was an error " \ - "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ - "`#{File.basename gemfile.to_s}`: #{e.message}" - - raise DSLError.new(message, gemfile, e.backtrace, contents) - ensure - @gemfile = original_gemfile - end - - def gemspec(opts = nil) - opts ||= {} - path = opts[:path] || "." - glob = opts[:glob] - name = opts[:name] - development_group = opts[:development_group] || :development - expanded_path = gemfile_root.join(path) - - gemspecs = Dir[File.join(expanded_path, "{,*}.gemspec")].map {|g| Bundler.load_gemspec(g) }.compact - gemspecs.reject! {|s| s.name != name } if name - Index.sort_specs(gemspecs) - specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } - - case specs_by_name_and_version.size - when 1 - specs = specs_by_name_and_version.values.first - spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first - - @gemspecs << spec - - gem_platforms = Bundler::Dependency::REVERSE_PLATFORM_MAP[Bundler::GemHelpers.generic_local_platform] - gem spec.name, :name => spec.name, :path => path, :glob => glob, :platforms => gem_platforms - - group(development_group) do - spec.development_dependencies.each do |dep| - gem dep.name, *(dep.requirement.as_list + [:type => :development]) - end - end - when 0 - raise InvalidOption, "There are no gemspecs at #{expanded_path}" - else - raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ - "Please use the :name option to specify which one should be used" - end - end - - def gem(name, *args) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - version = args || [">= 0"] - - normalize_options(name, version, options) - - dep = Dependency.new(name, version, options) - - # if there's already a dependency with this name we try to prefer one - if current = @dependencies.find {|d| d.name == dep.name } - deleted_dep = @dependencies.delete(current) if current.type == :development - - if current.requirement != dep.requirement - unless deleted_dep - return if dep.type == :development - 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})" - end - - else - Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ - "You should probably keep only one of them.\n" \ - "While it's not a problem now, it could cause errors if you change the version of one of them later." - end - - if current.source != dep.source - unless deleted_dep - return if dep.type == :development - raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ - "You specified that #{dep.name} (#{dep.requirement}) should come from " \ - "#{current.source || "an unspecified source"} and #{dep.source}\n" - end - end - end - - @dependencies << dep - end - - def source(source, *args, &blk) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - options = normalize_hash(options) - source = normalize_source(source) - - if options.key?("type") - options["type"] = options["type"].to_s - unless Plugin.source?(options["type"]) - raise InvalidOption, "No plugin sources available for #{options["type"]}" - end - - unless block_given? - raise InvalidOption, "You need to pass a block to #source with :type option" - end - - source_opts = options.merge("uri" => source) - with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) - elsif block_given? - with_source(@sources.add_rubygems_source("remotes" => source), &blk) - else - check_primary_source_safety(@sources) - @sources.global_rubygems_source = source - end - end - - def git_source(name, &block) - unless block_given? - raise InvalidOption, "You need to pass a block to #git_source" - end - - if valid_keys.include?(name.to_s) - raise InvalidOption, "You cannot use #{name} as a git source. It " \ - "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" - end - - @git_sources[name.to_s] = block - end - - def path(path, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a path source by itself. Instead, \n" \ - "either use the :path option on a gem, or specify the gems that \n" \ - "bundler should find in the path source by passing a block to \n" \ - "the path method, like: \n\n" \ - " path 'dir/containing/rails' do\n" \ - " gem 'rails'\n" \ - " end\n\n" - - raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? - SharedHelpers.major_deprecation(2, msg.strip) - end - - source_options = normalize_hash(options).merge( - "path" => Pathname.new(path), - "root_path" => gemfile_root, - "gemspec" => gemspecs.find {|g| g.name == options["name"] } - ) - source = @sources.add_path_source(source_options) - with_source(source, &blk) - end - - def git(uri, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a git source by itself. Instead, \n" \ - "either use the :git option on a gem, or specify the gems that \n" \ - "bundler should find in the git source by passing a block to \n" \ - "the git method, like: \n\n" \ - " git 'git://github.com/rails/rails.git' do\n" \ - " gem 'rails'\n" \ - " end" - raise DeprecatedError, msg - end - - with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) - end - - def github(repo, options = {}) - 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) - git_options = normalize_hash(options).merge("uri" => github_uri) - git_source = @sources.add_git_source(git_options) - with_source(git_source) { yield } - end - - def to_definition(lockfile, unlock) - Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) - end - - def group(*args, &blk) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - normalize_group_options(options, args) - - @groups.concat args - - if options["optional"] - optional_groups = args - @optional_groups - @optional_groups.concat optional_groups - end - - yield - ensure - args.each { @groups.pop } - end - - def install_if(*args) - @install_conditionals.concat args - yield - ensure - args.each { @install_conditionals.pop } - end - - def platforms(*platforms) - @platforms.concat platforms - yield - ensure - platforms.each { @platforms.pop } - end - alias_method :platform, :platforms - - def env(name) - old = @env - @env = name - yield - ensure - @env = old - end - - def plugin(*args) - # Pass on - end - - def method_missing(name, *args) - raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" - end - - private - - def add_git_sources - return if Bundler.feature_flag.skip_default_git_sources? - - 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 - # can break deployment of existing locked bundles when switching between - # different versions of Bundler. The change will be made in 2.0, which - # does not guarantee compatibility with the 1.x series. - # - # See https://github.com/bundler/bundler/pull/2569 for discussion - # - # This can be overridden by adding this code to your Gemfiles: - # - # git_source(:github) do |repo_name| - # repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") - # "https://github.com/#{repo_name}.git" - # end - repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") - # TODO: 2.0 upgrade this setting to the default - if Bundler.settings["github.https"] - Bundler::SharedHelpers.major_deprecation 2, "The `github.https` setting will be removed" - "https://github.com/#{repo_name}.git" - else - "git://github.com/#{repo_name}.git" - end - end - - # TODO: 2.0 remove this deprecated git source - git_source(:gist) do |repo_name| - warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"') - - "https://gist.github.com/#{repo_name}.git" - end - - # TODO: 2.0 remove this deprecated git source - git_source(:bitbucket) do |repo_name| - warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip) -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 - "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" - end - end - - def with_source(source) - old_source = @source - if block_given? - @source = source - yield - end - source - ensure - @source = old_source - end - - def normalize_hash(opts) - opts.keys.each do |k| - opts[k.to_s] = opts.delete(k) unless k.is_a?(String) - end - opts - end - - def valid_keys - @valid_keys ||= VALID_KEYS - end - - def normalize_options(name, version, opts) - if name.is_a?(Symbol) - raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) - end - if name =~ /\s/ - raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) - end - if name.empty? - raise GemfileError, %(an empty gem name is not valid) - end - - normalize_hash(opts) - - git_names = @git_sources.keys.map(&:to_s) - validate_keys("gem '#{name}'", opts, valid_keys + git_names) - - groups = @groups.dup - opts["group"] = opts.delete("groups") || opts["group"] - groups.concat Array(opts.delete("group")) - groups = [:default] if groups.empty? - - install_if = @install_conditionals.dup - install_if.concat Array(opts.delete("install_if")) - install_if = install_if.reduce(true) do |memo, val| - memo && (val.respond_to?(:call) ? val.call : val) - end - - platforms = @platforms.dup - opts["platforms"] = opts["platform"] || opts["platforms"] - platforms.concat Array(opts.delete("platforms")) - platforms.map!(&:to_sym) - platforms.each do |p| - next if VALID_PLATFORMS.include?(p) - raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" - end - - # Save sources passed in a key - if opts.key?("source") - source = normalize_source(opts["source"]) - opts["source"] = @sources.add_rubygems_source("remotes" => source) - end - - git_name = (git_names & opts.keys).last - if @git_sources[git_name] - opts["git"] = @git_sources[git_name].call(opts[git_name]) - end - - %w[git path].each do |type| - next unless param = opts[type] - if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ - options = opts.merge("name" => name, "version" => $1) - else - options = opts.dup - end - source = send(type, param, options) {} - opts["source"] = source - end - - opts["source"] ||= @source - opts["env"] ||= @env - opts["platforms"] = platforms.dup - opts["group"] = groups - opts["should_include"] = install_if - end - - def normalize_group_options(opts, groups) - normalize_hash(opts) - - groups = groups.map {|group| ":#{group}" }.join(", ") - validate_keys("group #{groups}", opts, %w[optional]) - - opts["optional"] ||= false - end - - def validate_keys(command, opts, valid_keys) - invalid_keys = opts.keys - valid_keys - - git_source = opts.keys & @git_sources.keys.map(&:to_s) - if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?) - raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) - end - - return true unless invalid_keys.any? - - message = String.new - message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " - message << if invalid_keys.size > 1 - "as options for #{command}, but they are invalid." - else - "as an option for #{command}, but it is invalid." - end - - message << " Valid options are: #{valid_keys.join(", ")}." - message << " You may be able to resolve this by upgrading Bundler to the newest version." - raise InvalidOption, message - end - - def normalize_source(source) - case source - when :gemcutter, :rubygems, :rubyforge - Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \ - "requests are insecure.\nPlease change your source to 'https://" \ - "rubygems.org' if possible, or 'http://rubygems.org' if not." - "http://rubygems.org" - when String - source - else - raise GemfileError, "Unknown source '#{source}'" - end - end - - def check_primary_source_safety(source_list) - return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? - - if Bundler.feature_flag.disable_multisource? - msg = "This Gemfile contains multiple primary sources. " \ - "Each source after the first must include a block to indicate which gems " \ - "should come from that source" - unless Bundler.feature_flag.bundler_2_mode? - msg += ". To downgrade this error to a warning, run " \ - "`bundle config --delete disable_multisource`" - end - raise GemfileEvalError, msg - else - Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source. " \ - "To upgrade this warning to an error, run `bundle config " \ - "disable_multisource true`." - end - end - - def warn_deprecated_git_source(name, replacement, additional_message = nil) - # TODO: 2.0 remove deprecation - additional_message &&= " #{additional_message}" - replacement = if replacement.count("\n").zero? - "{|repo_name| #{replacement} }" - else - "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end" - end - - Bundler::SharedHelpers.major_deprecation 2, <<-EOS -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: - - git_source(:#{name}) #{replacement} - - EOS - end - - class DSLError < GemfileError - # @return [String] the description that should be presented to the user. - # - attr_reader :description - - # @return [String] the path of the dsl file that raised the exception. - # - attr_reader :dsl_path - - # @return [Exception] the backtrace of the exception raised by the - # evaluation of the dsl file. - # - attr_reader :backtrace - - # @param [Exception] backtrace @see backtrace - # @param [String] dsl_path @see dsl_path - # - def initialize(description, dsl_path, backtrace, contents = nil) - @status_code = $!.respond_to?(:status_code) && $!.status_code - - @description = description - @dsl_path = dsl_path - @backtrace = backtrace - @contents = contents - end - - def status_code - @status_code || super - end - - # @return [String] the contents of the DSL that cause the exception to - # be raised. - # - def contents - @contents ||= begin - dsl_path && File.exist?(dsl_path) && File.read(dsl_path) - end - end - - # The message of the exception reports the content of podspec for the - # line that generated the original exception. - # - # @example Output - # - # Invalid podspec at `RestKit.podspec` - undefined method - # `exclude_header_search_paths=' for #<Pod::Specification for - # `RestKit/Network (0.9.3)`> - # - # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 - # ------------------------------------------- - # # because it would break: #import <CoreData/CoreData.h> - # > ns.exclude_header_search_paths = 'Code/RestKit.h' - # end - # ------------------------------------------- - # - # @return [String] the message of the exception. - # - def to_s - @to_s ||= begin - trace_line, description = parse_line_number_from_description - - m = String.new("\n[!] ") - m << description - m << ". Bundler cannot continue.\n" - - return m unless backtrace && dsl_path && contents - - trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line - return m unless trace_line - line_numer = trace_line.split(":")[1].to_i - 1 - return m unless line_numer - - lines = contents.lines.to_a - indent = " # " - indicator = indent.tr("#", ">") - first_line = line_numer.zero? - last_line = (line_numer == (lines.count - 1)) - - m << "\n" - m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" - m << "#{indent}-------------------------------------------\n" - m << "#{indent}#{lines[line_numer - 1]}" unless first_line - m << "#{indicator}#{lines[line_numer]}" - m << "#{indent}#{lines[line_numer + 1]}" unless last_line - m << "\n" unless m.end_with?("\n") - m << "#{indent}-------------------------------------------\n" - end - end - - private - - def parse_line_number_from_description - description = self.description - if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/ - trace_line = Regexp.last_match[1] - description = description.sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") - end - [trace_line, description] - end - end - - def gemfile_root - @gemfile ||= Bundler.default_gemfile - @gemfile.dirname - end - end -end diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb deleted file mode 100644 index 8668c4ea7f..0000000000 --- a/lib/bundler/endpoint_specification.rb +++ /dev/null @@ -1,141 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # used for Creating Specifications from the Gemcutter Endpoint - class EndpointSpecification < Gem::Specification - ILLFORMED_MESSAGE = 'Ill-formed requirement ["#<YAML::Syck::DefaultKey'.freeze - include MatchPlatform - - attr_reader :name, :version, :platform, :required_rubygems_version, :required_ruby_version, :checksum - attr_accessor :source, :remote, :dependencies - - def initialize(name, version, platform, dependencies, metadata = nil) - super() - @name = name - @version = Gem::Version.create version - @platform = platform - @dependencies = dependencies.map {|dep, reqs| build_dependency(dep, reqs) } - - @loaded_from = nil - @remote_specification = nil - - parse_metadata(metadata) - end - - def fetch_platform - @platform - end - - # needed for standalone, load required_paths from local gemspec - # after the gem is installed - def require_paths - if @remote_specification - @remote_specification.require_paths - elsif _local_specification - _local_specification.require_paths - else - super - end - end - - # needed for inline - def load_paths - # remote specs aren't installed, and can't have load_paths - if _local_specification - _local_specification.load_paths - else - super - end - end - - # needed for binstubs - def executables - if @remote_specification - @remote_specification.executables - elsif _local_specification - _local_specification.executables - else - super - end - end - - # needed for bundle clean - def bindir - if @remote_specification - @remote_specification.bindir - elsif _local_specification - _local_specification.bindir - else - super - end - end - - # needed for post_install_messages during install - def post_install_message - if @remote_specification - @remote_specification.post_install_message - elsif _local_specification - _local_specification.post_install_message - else - super - end - end - - # needed for "with native extensions" during install - def extensions - if @remote_specification - @remote_specification.extensions - elsif _local_specification - _local_specification.extensions - else - super - end - end - - def _local_specification - return unless @loaded_from && File.exist?(local_specification_path) - eval(File.read(local_specification_path)).tap do |spec| - spec.loaded_from = @loaded_from - end - end - - def __swap__(spec) - SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) - @remote_specification = spec - end - - private - - def local_specification_path - "#{base_dir}/specifications/#{full_name}.gemspec" - end - - def parse_metadata(data) - return unless data - data.each do |k, v| - next unless v - case k.to_s - when "checksum" - @checksum = v.last - when "rubygems" - @required_rubygems_version = Gem::Requirement.new(v) - when "ruby" - @required_ruby_version = Gem::Requirement.new(v) - end - end - rescue => e - raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" - end - - def build_dependency(name, requirements) - Gem::Dependency.new(name, requirements) - rescue ArgumentError => e - raise unless e.message.include?(ILLFORMED_MESSAGE) - puts # we shouldn't print the error message on the "fetching info" status line - raise GemspecError, - "Unfortunately, the gem #{name} (#{version}) has an invalid " \ - "gemspec.\nPlease ask the gem author to yank the bad version to fix " \ - "this issue. For more information, see http://bit.ly/syck-defaultkey." - end - end -end diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb deleted file mode 100644 index 58fe20dbe7..0000000000 --- a/lib/bundler/env.rb +++ /dev/null @@ -1,153 +0,0 @@ -# frozen_string_literal: true - -require "bundler/rubygems_integration" -require "bundler/source/git/git_proxy" - -module Bundler - class Env - def self.write(io) - io.write report - end - - def self.report(options = {}) - print_gemfile = options.delete(:print_gemfile) { true } - print_gemspecs = options.delete(:print_gemspecs) { true } - - out = String.new - append_formatted_table("Environment", environment, out) - append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) - - unless Bundler.settings.all.empty? - out << "\n## Bundler settings\n\n```\n" - Bundler.settings.all.each do |setting| - out << setting << "\n" - Bundler.settings.pretty_values_for(setting).each do |line| - out << " " << line << "\n" - end - end - out << "```\n" - end - - return out unless SharedHelpers.in_bundle? - - if print_gemfile - gemfiles = [Bundler.default_gemfile] - begin - gemfiles = Bundler.definition.gemfiles - rescue GemfileNotFound - nil - end - - out << "\n## Gemfile\n" - gemfiles.each do |gemfile| - 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" << read_file(Bundler.default_lockfile).chomp << "\n```\n" - end - - if print_gemspecs - dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } - out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? - dsl.gemspecs.each do |gs| - out << "\n### #{File.basename(gs.loaded_from)}" - out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" - end - end - - out - end - - def self.read_file(filename) - File.read(filename.to_s).strip - rescue Errno::ENOENT - "<No #{filename} found>" - rescue => e - "#{e.class}: #{e.message}" - end - - def self.ruby_version - str = String.new("#{RUBY_VERSION}") - if RUBY_VERSION < "1.9" - str << " (#{RUBY_RELEASE_DATE}" - str << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - str << ") [#{RUBY_PLATFORM}]" - else - str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]" - end - end - - def self.git_version - Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version - rescue Bundler::Source::Git::GitNotInstalledError - "not installed" - 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 diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb deleted file mode 100644 index af7c1ef0a4..0000000000 --- a/lib/bundler/environment_preserver.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Bundler - 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 keys [Array<String>] - def initialize(env, keys) - @original = env.to_hash - @keys = keys - @prefix = BUNDLER_PREFIX - end - - # @return [Hash] - def backup - env = @original.clone - @keys.each do |key| - value = env[key] - if !value.nil? && !value.empty? - env[@prefix + key] ||= value - elsif value.nil? - env[@prefix + key] ||= INTENTIONALLY_NIL - end - end - env - end - - # @return [Hash] - def restore - env = @original.clone - @keys.each do |key| - value_original = env[@prefix + key] - next if value_original.nil? || value_original.empty? - if value_original == INTENTIONALLY_NIL - env.delete(key) - else - env[key] = value_original - end - env.delete(@prefix + key) - end - env - end - end -end diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb deleted file mode 100644 index e471bce0b6..0000000000 --- a/lib/bundler/errors.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class BundlerError < StandardError - def self.status_code(code) - define_method(:status_code) { code } - if match = BundlerError.all_errors.find {|_k, v| v == code } - error, _ = match - raise ArgumentError, - "Trying to register #{self} for status code #{code} but #{error} is already registered" - end - BundlerError.all_errors[self] = code - end - - def self.all_errors - @all_errors ||= {} - end - end - - class GemfileError < BundlerError; status_code(4); end - class InstallError < BundlerError; status_code(5); end - - # Internal error, should be rescued - class VersionConflict < BundlerError - attr_reader :conflicts - - def initialize(conflicts, msg = nil) - super(msg) - @conflicts = conflicts - end - - status_code(6) - end - - class GemNotFound < BundlerError; status_code(7); end - class InstallHookError < BundlerError; status_code(8); end - class GemfileNotFound < BundlerError; status_code(10); end - class GitError < BundlerError; status_code(11); end - class DeprecatedError < BundlerError; status_code(12); end - class PathError < BundlerError; status_code(13); end - class GemspecError < BundlerError; status_code(14); end - class InvalidOption < BundlerError; status_code(15); end - class ProductionError < BundlerError; status_code(16); end - class HTTPError < BundlerError - status_code(17) - def filter_uri(uri) - URICredentialsFilter.credential_filtered_uri(uri) - end - end - class RubyVersionMismatch < BundlerError; status_code(18); end - class SecurityError < BundlerError; status_code(19); end - class LockfileError < BundlerError; status_code(20); end - class CyclicDependencyError < BundlerError; status_code(21); end - class GemfileLockNotFound < BundlerError; status_code(22); end - class PluginError < BundlerError; status_code(29); end - class SudoNotPermittedError < BundlerError; status_code(30); end - class ThreadCreationError < BundlerError; status_code(33); end - class APIResponseMismatchError < BundlerError; status_code(34); end - class GemfileEvalError < GemfileError; end - class MarshalError < StandardError; end - - class PermissionError < BundlerError - def initialize(path, permission_type = :write) - @path = path - @permission_type = permission_type - end - - def action - case @permission_type - when :read then "read from" - when :write then "write to" - when :executable, :exec then "execute" - else @permission_type.to_s - end - end - - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "It is likely that you need to grant #{@permission_type} permissions " \ - "for that path." - end - - status_code(23) - end - - class GemRequireError < BundlerError - attr_reader :orig_exception - - def initialize(orig_exception, msg) - full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ - "Backtrace for gem load error is:\n"\ - "#{orig_exception.backtrace.join("\n")}\n"\ - "Bundler Error Backtrace:\n" - super(full_message) - @orig_exception = orig_exception - end - - status_code(24) - end - - class YamlSyntaxError < BundlerError - attr_reader :orig_exception - - def initialize(orig_exception, msg) - super(msg) - @orig_exception = orig_exception - end - - status_code(25) - end - - class TemporaryResourceError < PermissionError - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "Some resource was temporarily unavailable. It's suggested that you try" \ - "the operation again." - end - - status_code(26) - end - - class VirtualProtocolError < BundlerError - def message - "There was an error relating to virtualization and file access." \ - "It is likely that you need to grant access to or mount some file system correctly." - end - - status_code(27) - end - - class OperationNotSupportedError < PermissionError - def message - "Attempting to #{action} `#{@path}` is unsupported by your OS." - end - - status_code(28) - end - - class NoSpaceOnDeviceError < PermissionError - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "There was insufficient space remaining on the device." - end - - status_code(31) - end - - class GenericSystemCallError < BundlerError - attr_reader :underlying_error - - def initialize(underlying_error, message) - @underlying_error = underlying_error - super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") - end - - status_code(32) - end -end diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb deleted file mode 100644 index 6a1809cd40..0000000000 --- a/lib/bundler/feature_flag.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class FeatureFlag - def self.settings_flag(flag, &default) - 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" - end - - 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 - end - end - private_class_method :settings_method - - (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(: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(: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) - @bundler_version = Gem::Version.create(bundler_version) - end - - def major_version - @bundler_version.segments.first - end - private :major_version - end -end diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb deleted file mode 100644 index 03ff528826..0000000000 --- a/lib/bundler/fetcher.rb +++ /dev/null @@ -1,312 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_persistent" -require "cgi" -require "securerandom" -require "zlib" - -module Bundler - # Handles all the fetching with the rubygems server - class Fetcher - autoload :CompactIndex, "bundler/fetcher/compact_index" - autoload :Downloader, "bundler/fetcher/downloader" - autoload :Dependency, "bundler/fetcher/dependency" - autoload :Index, "bundler/fetcher/index" - - # This error is raised when it looks like the network is down - class NetworkDownError < HTTPError; end - # This error is raised if the API returns a 413 (only printed in verbose) - class FallbackError < HTTPError; end - # This is the error raised if OpenSSL fails the cert verification - class CertificateFailureError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ - " is a chance you are experiencing a man-in-the-middle attack, but" \ - " most likely your system doesn't have the CA certificates needed" \ - " for verification. For information about OpenSSL certificates, see" \ - " http://bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \ - " sources and change 'https' to 'http'." - end - end - # This is the error raised when a source is HTTPS and OpenSSL didn't load - class SSLError < HTTPError - def initialize(msg = nil) - super msg || "Could not load OpenSSL.\n" \ - "You must recompile Ruby with OpenSSL support or change the sources in your " \ - "Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL " \ - "using RVM are available at rvm.io/packages/openssl." - end - end - # This error is raised if HTTP authentication is required, but not provided. - class AuthenticationRequiredError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Authentication is required for #{remote_uri}.\n" \ - "Please supply credentials for this source. You can do this by running:\n" \ - " bundle config #{remote_uri} username:password" - end - end - # This error is raised if HTTP authentication is provided, but incorrect. - class BadAuthenticationError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Bad username or password for #{remote_uri}.\n" \ - "Please double-check your credentials and correct them." - end - end - - # Exceptions classes that should bypass retry attempts. If your password didn't work the - # first time, it's not going to the third time. - NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency, - :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed, - :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound, - :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge, - :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, - :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze - FAIL_ERRORS = begin - fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError] - fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError) - fail_errors.concat(NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact) - end.freeze - - class << self - attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries - end - - self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request - self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call - self.max_retries = Bundler.settings[:retry] # How many retries for the API call - - def initialize(remote) - @remote = remote - - Socket.do_not_reverse_lookup = true - connection # create persistent connection - end - - def uri - @remote.anonymized_uri - end - - # fetch a gem specification - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - spec_file_name = "#{spec.join "-"}.gemspec" - - uri = URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") - if uri.scheme == "file" - Bundler.load_marshal Gem.inflate(Gem.read_binary(uri.path)) - elsif cached_spec_path = gemspec_cached_path(spec_file_name) - Bundler.load_gemspec(cached_spec_path) - else - Bundler.load_marshal Gem.inflate(downloader.fetch(uri).body) - end - rescue MarshalError - raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ - "Your network or your gem server is probably having issues right now." - end - - # return the specs in the bundler format as an index with retries - def specs_with_retry(gem_names, source) - Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do - specs(gem_names, source) - end - end - - # return the specs in the bundler format as an index - def specs(gem_names, source) - old = Bundler.rubygems.sources - index = Bundler::Index.new - - if Bundler::Fetcher.disable_endpoint - @use_api = false - specs = fetchers.last.specs(gem_names) - else - specs = [] - fetchers.shift until fetchers.first.available? || fetchers.empty? - fetchers.dup.each do |f| - break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names) - fetchers.delete(f) - end - @use_api = false if fetchers.none?(&:api_fetcher?) - end - - specs.each do |name, version, platform, dependencies, metadata| - next if name == "bundler" - spec = if dependencies - EndpointSpecification.new(name, version, platform, dependencies, metadata) - else - RemoteSpecification.new(name, version, platform, self) - end - spec.source = source - spec.remote = @remote - index << spec - end - - index - rescue CertificateFailureError - Bundler.ui.info "" if gem_names && use_api # newline after dots - raise - ensure - Bundler.rubygems.sources = old - end - - def use_api - return @use_api if defined?(@use_api) - - fetchers.shift until fetchers.first.available? - - @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint - false - else - fetchers.first.api_fetcher? - end - end - - def user_agent - @user_agent ||= begin - ruby = Bundler::RubyVersion.system - - agent = String.new("bundler/#{Bundler::VERSION}") - agent << " rubygems/#{Gem::VERSION}" - agent << " ruby/#{ruby.versions_string(ruby.versions)}" - agent << " (#{ruby.host})" - agent << " command/#{ARGV.first}" - - if ruby.engine != "ruby" - # engine_version raises on unknown engines - engine_version = begin - ruby.engine_versions - rescue - "???" - end - agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" - end - - agent << " options/#{Bundler.settings.all.join(",")}" - - agent << " ci/#{cis.join(",")}" if cis.any? - - # add a random ID so we can consolidate runs server-side - agent << " " << SecureRandom.hex(8) - - # add any user agent strings set in the config - extra_ua = Bundler.settings[:user_agent] - agent << " " << extra_ua if extra_ua - - agent - end - end - - def fetchers - @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) } - end - - def http_proxy - return unless uri = connection.proxy_uri - uri.to_s - end - - def inspect - "#<#{self.class}:0x#{object_id} uri=#{uri}>" - end - - private - - FETCHERS = [CompactIndex, Dependency, Index].freeze - - def cis - env_cis = { - "TRAVIS" => "travis", - "CIRCLECI" => "circle", - "SEMAPHORE" => "semaphore", - "JENKINS_URL" => "jenkins", - "BUILDBOX" => "buildbox", - "GO_SERVER_URL" => "go", - "SNAP_CI" => "snap", - "CI_NAME" => ENV["CI_NAME"], - "CI" => "ci" - } - env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci } - end - - def connection - @connection ||= begin - needs_ssl = remote_uri.scheme == "https" || - Bundler.settings[:ssl_verify_mode] || - Bundler.settings[:ssl_client_cert] - raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) - - con = PersistentHTTP.new "bundler", :ENV - if gem_proxy = Bundler.rubygems.configuration[:http_proxy] - con.proxy = URI.parse(gem_proxy) if gem_proxy != :no_proxy - end - - if remote_uri.scheme == "https" - con.verify_mode = (Bundler.settings[:ssl_verify_mode] || - OpenSSL::SSL::VERIFY_PEER) - con.cert_store = bundler_cert_store - end - - ssl_client_cert = 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.key = OpenSSL::PKey::RSA.new(pem) - end - - con.read_timeout = Fetcher.api_timeout - con.open_timeout = Fetcher.api_timeout - con.override_headers["User-Agent"] = user_agent - con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri - con - end - end - - # cached gem specification path, if one exists - def gemspec_cached_path(spec_file_name) - paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } - paths = paths.select {|path| File.file? path } - paths.first - end - - HTTP_ERRORS = [ - Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, - Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, - Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, - PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH - ].freeze - - def bundler_cert_store - store = OpenSSL::X509::Store.new - ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || - (Bundler.rubygems.configuration.ssl_ca_cert if - 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 - store.add_file ssl_ca_cert - end - else - store.set_default_paths - certs = File.expand_path("../ssl_certs/*/*.pem", __FILE__) - Dir.glob(certs).each {|c| store.add_file c } - end - store - end - - private - - def remote_uri - @remote.uri - end - - def downloader - @downloader ||= Downloader.new(connection, self.class.redirect_limit) - end - end -end diff --git a/lib/bundler/fetcher/base.rb b/lib/bundler/fetcher/base.rb deleted file mode 100644 index 27987f670a..0000000000 --- a/lib/bundler/fetcher/base.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Fetcher - class Base - attr_reader :downloader - attr_reader :display_uri - attr_reader :remote - - def initialize(downloader, remote, display_uri) - raise "Abstract class" if self.class == Base - @downloader = downloader - @remote = remote - @display_uri = display_uri - end - - def remote_uri - @remote.uri - end - - def fetch_uri - @fetch_uri ||= begin - if remote_uri.host == "rubygems.org" - uri = remote_uri.dup - uri.host = "index.rubygems.org" - uri - else - remote_uri - end - end - end - - def available? - true - end - - def api_fetcher? - false - end - - private - - def log_specs(debug_msg) - if Bundler.ui.debug? - Bundler.ui.debug debug_msg - else - Bundler.ui.info ".", false - end - end - end - end -end diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb deleted file mode 100644 index cfc74d642c..0000000000 --- a/lib/bundler/fetcher/compact_index.rb +++ /dev/null @@ -1,126 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "bundler/worker" - -module Bundler - autoload :CompactIndexClient, "bundler/compact_index_client" - - class Fetcher - class CompactIndex < Base - def self.compact_index_request(method_name) - method = instance_method(method_name) - undef_method(method_name) - define_method(method_name) do |*args, &blk| - begin - method.bind(self).call(*args, &blk) - rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e - raise HTTPError, e.message - rescue AuthenticationRequiredError - # Fail since we got a 401 from the server. - raise - rescue HTTPError => e - Bundler.ui.trace(e) - nil - end - end - end - - def specs(gem_names) - specs_for_names(gem_names) - end - compact_index_request :specs - - def specs_for_names(gem_names) - gem_info = [] - complete_gems = [] - remaining_gems = gem_names.dup - - until remaining_gems.empty? - log_specs "Looking up gems #{remaining_gems.inspect}" - - deps = compact_index_client.dependencies(remaining_gems) - next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq - deps.each {|dep| gem_info << dep } - complete_gems.concat(deps.map(&:first)).uniq! - remaining_gems = next_gems - complete_gems - end - @bundle_worker.stop if @bundle_worker - @bundle_worker = nil # reset it. Not sure if necessary - - gem_info - end - - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - contents = compact_index_client.spec(*spec) - return nil if contents.nil? - contents.unshift(spec.first) - contents[3].map! {|d| Gem::Dependency.new(*d) } - EndpointSpecification.new(*contents) - end - compact_index_request :fetch_spec - - def available? - return nil unless SharedHelpers.md5_available? - user_home = Bundler.user_home - 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 - fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums! - rescue CompactIndexClient::Updater::MisMatchedChecksumError => e - Bundler.ui.debug(e.message) - nil - end - compact_index_request :available? - - def api_fetcher? - true - end - - private - - def compact_index_client - @compact_index_client ||= begin - SharedHelpers.filesystem_access(cache_path) do - CompactIndexClient.new(cache_path, client_fetcher) - end.tap do |client| - client.in_parallel = lambda do |inputs, &blk| - func = lambda {|object, _index| blk.call(object) } - worker = bundle_worker(func) - inputs.each {|input| worker.enq(input) } - inputs.map { worker.deq } - end - end - end - end - - def bundle_worker(func = nil) - @bundle_worker ||= begin - worker_name = "Compact Index (#{display_uri.host})" - Bundler::Worker.new(Bundler.current_ruby.rbx? ? 1 : 25, worker_name, func) - end - @bundle_worker.tap do |worker| - worker.instance_variable_set(:@func, func) if func - end - end - - def cache_path - Bundler.user_cache.join("compact_index", remote.cache_slug) - end - - def client_fetcher - ClientFetcher.new(self, Bundler.ui) - end - - ClientFetcher = Struct.new(:fetcher, :ui) do - def call(path, headers) - fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) - rescue NetworkDownError => e - raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] - ui.warn "Using the cached data for the new index because of a network error: #{e}" - Net::HTTPNotModified.new(nil, nil, nil) - end - end - end - end -end diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb deleted file mode 100644 index 1430d1ebeb..0000000000 --- a/lib/bundler/fetcher/dependency.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "cgi" - -module Bundler - class Fetcher - class Dependency < Base - def available? - @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) - rescue NetworkDownError => e - raise HTTPError, e.message - rescue AuthenticationRequiredError - # Fail since we got a 401 from the server. - raise - rescue HTTPError - false - end - - def api_fetcher? - true - end - - def specs(gem_names, full_dependency_list = [], last_spec_list = []) - query_list = gem_names.uniq - full_dependency_list - - log_specs "Query List: #{query_list.inspect}" - - return last_spec_list if query_list.empty? - - spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do - dependency_specs(query_list) - end - - returned_gems = spec_list.map(&:first).uniq - specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) - rescue MarshalError - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - Bundler.ui.debug "could not fetch from the dependency API, trying the full index" - nil - rescue HTTPError, GemspecError - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`" - nil - end - - def dependency_specs(gem_names) - Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" - - gem_list = unmarshalled_dep_gems(gem_names) - get_formatted_specs_and_deps(gem_list) - end - - def unmarshalled_dep_gems(gem_names) - gem_list = [] - gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names| - marshalled_deps = downloader.fetch(dependency_api_uri(names)).body - gem_list.concat(Bundler.load_marshal(marshalled_deps)) - end - gem_list - end - - def get_formatted_specs_and_deps(gem_list) - deps_list = [] - spec_list = [] - - gem_list.each do |s| - deps_list.concat(s[:dependencies].map(&:first)) - deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } - spec_list.push([s[:name], s[:number], s[:platform], deps]) - end - [spec_list, deps_list] - end - - def dependency_api_uri(gem_names = []) - uri = fetch_uri + "api/v1/dependencies" - uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? - uri - end - end - end -end diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb deleted file mode 100644 index cbc5e220bd..0000000000 --- a/lib/bundler/fetcher/downloader.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Fetcher - class Downloader - attr_reader :connection - attr_reader :redirect_limit - - def initialize(connection, redirect_limit) - @connection = connection - @redirect_limit = redirect_limit - end - - def fetch(uri, options = {}, counter = 0) - raise HTTPError, "Too many redirects" if counter >= redirect_limit - - response = request(uri, options) - Bundler.ui.debug("HTTP #{response.code} #{response.message} #{uri}") - - case response - when Net::HTTPSuccess, Net::HTTPNotModified - response - when Net::HTTPRedirection - new_uri = URI.parse(response["location"]) - if new_uri.host == uri.host - new_uri.user = uri.user - new_uri.password = uri.password - end - fetch(new_uri, options, counter + 1) - when Net::HTTPRequestEntityTooLarge - raise FallbackError, response.body - when Net::HTTPUnauthorized - raise AuthenticationRequiredError, uri.host - when Net::HTTPNotFound - raise FallbackError, "Net::HTTPNotFound" - else - raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" - end - end - - def request(uri, options) - validate_uri_scheme!(uri) - - Bundler.ui.debug "HTTP GET #{uri}" - req = Net::HTTP::Get.new uri.request_uri, options - if uri.user - user = CGI.unescape(uri.user) - password = uri.password ? CGI.unescape(uri.password) : nil - req.basic_auth(user, password) - end - connection.request(uri, req) - rescue NoMethodError => e - raise unless ["undefined method", "use_ssl="].all? {|snippet| e.message.include? snippet } - raise LoadError.new("cannot load such file -- openssl") - rescue OpenSSL::SSL::SSLError - raise CertificateFailureError.new(uri) - rescue *HTTP_ERRORS => e - Bundler.ui.trace e - case e.message - when /host down:/, /getaddrinfo: nodename nor servname provided/ - raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ - "connection and try again." - else - raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" \ - " (#{e})" - end - end - - private - - def validate_uri_scheme!(uri) - return if uri.scheme =~ /\Ahttps?\z/ - raise InvalidOption, - "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ - "Did you mean `http` or `https`?" - end - end - end -end diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb deleted file mode 100644 index 9529944391..0000000000 --- a/lib/bundler/fetcher/index.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "rubygems/remote_fetcher" - -module Bundler - class Fetcher - class Index < Base - def specs(_gem_names) - Bundler.rubygems.fetch_all_remote_specs(remote) - rescue Gem::RemoteFetcher::FetchError, OpenSSL::SSL::SSLError, Net::HTTPFatalError => e - case e.message - when /certificate verify failed/ - raise CertificateFailureError.new(display_uri) - when /401/ - raise AuthenticationRequiredError, remote_uri - when /403/ - raise BadAuthenticationError, remote_uri if remote_uri.userinfo - raise AuthenticationRequiredError, remote_uri - else - Bundler.ui.trace e - raise HTTPError, "Could not fetch specs from #{display_uri}" - end - end - - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - spec_file_name = "#{spec.join "-"}.gemspec" - - uri = URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") - if uri.scheme == "file" - Bundler.load_marshal Gem.inflate(Gem.read_binary(uri.path)) - elsif cached_spec_path = gemspec_cached_path(spec_file_name) - Bundler.load_gemspec(cached_spec_path) - else - Bundler.load_marshal Gem.inflate(downloader.fetch(uri).body) - end - rescue MarshalError - raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ - "Your network or your gem server is probably having issues right now." - end - - private - - # cached gem specification path, if one exists - def gemspec_cached_path(spec_file_name) - paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } - paths.find {|path| File.file? path } - end - end - end -end diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb deleted file mode 100644 index f624185773..0000000000 --- a/lib/bundler/friendly_errors.rb +++ /dev/null @@ -1,129 +0,0 @@ -# encoding: utf-8 -# frozen_string_literal: true - -require "cgi" -require "bundler/vendored_thor" - -module Bundler - module FriendlyErrors - module_function - - def log_error(error) - case error - when YamlSyntaxError - Bundler.ui.error error.message - Bundler.ui.trace error.orig_exception - when Dsl::DSLError, GemspecError - Bundler.ui.error error.message - when GemRequireError - Bundler.ui.error error.message - Bundler.ui.trace error.orig_exception, nil, true - when BundlerError - Bundler.ui.error error.message, :wrap => true - Bundler.ui.trace error - when Thor::Error - Bundler.ui.error error.message - when LoadError - raise error unless error.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ - Bundler.ui.error "\nCould not load OpenSSL." - Bundler.ui.warn <<-WARN, :wrap => true - You must recompile Ruby with OpenSSL support or change the sources in your \ - Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \ - using RVM are available at http://rvm.io/packages/openssl. - WARN - Bundler.ui.trace error - when Interrupt - Bundler.ui.error "\nQuitting..." - Bundler.ui.trace error - when Gem::InvalidSpecificationException - Bundler.ui.error error.message, :wrap => true - when SystemExit - when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact - Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ - "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ - "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ - "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." - else request_issue_report_for(error) - end - end - - def exit_status(error) - case error - when BundlerError then error.status_code - when Thor::Error then 15 - when SystemExit then error.status - else 1 - end - end - - def request_issue_report_for(e) - Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") - --- ERROR REPORT TEMPLATE ------------------------------------------------------- - # Error Report - - ## Questions - - Please fill out answers to these questions, it'll help us figure out - why things are going wrong. - - - **What did you do?** - - I ran the command `#{$PROGRAM_NAME} #{ARGV.join(" ")}` - - - **What did you expect to happen?** - - I expected Bundler to... - - - **What happened instead?** - - Instead, what happened was... - - - **Have you tried any solutions posted on similar issues in our issue tracker, stack overflow, or google?** - - I tried... - - - **Have you read our issues document, https://github.com/bundler/bundler/blob/master/doc/contributing/ISSUES.md?** - - ... - - ## Backtrace - - ``` - #{e.class}: #{e.message} - #{e.backtrace && e.backtrace.join("\n ").chomp} - ``` - - #{Bundler::Env.report} - --- TEMPLATE END ---------------------------------------------------------------- - - EOS - - Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." - - Bundler.ui.warn <<-EOS.gsub(/^ {8}/, "") - - First, try this link to see if there are any existing issue reports for this error: - #{issues_url(e)} - - If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: - https://github.com/bundler/bundler/issues/new - EOS - end - - def issues_url(exception) - message = exception.message.lines.first.tr(":", " ").chomp - message = message.split("-").first if exception.is_a?(Errno) - "https://github.com/bundler/bundler/search?q=" \ - "#{CGI.escape(message)}&type=Issues" - end - end - - def self.with_friendly_errors - yield - rescue SignalException - raise - rescue Exception => e - FriendlyErrors.log_error(e) - exit FriendlyErrors.exit_status(e) - end -end diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb deleted file mode 100644 index 1d7fc508d5..0000000000 --- a/lib/bundler/gem_helper.rb +++ /dev/null @@ -1,202 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_thor" unless defined?(Thor) -require "bundler" - -module Bundler - class GemHelper - include Rake::DSL if defined? Rake::DSL - - class << self - # set when install'd. - attr_accessor :instance - - def install_tasks(opts = {}) - new(opts[:dir], opts[:name]).install - end - - def gemspec(&block) - gemspec = instance.gemspec - block.call(gemspec) if block - gemspec - end - end - - attr_reader :spec_path, :base, :gemspec - - def initialize(base = nil, name = nil) - Bundler.ui = UI::Shell.new - @base = (base ||= SharedHelpers.pwd) - gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "{,*}.gemspec")] - raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 - @spec_path = gemspecs.first - @gemspec = Bundler.load_gemspec(@spec_path) - end - - def install - built_gem_path = nil - - desc "Build #{name}-#{version}.gem into the pkg directory." - task "build" do - built_gem_path = build_gem - end - - desc "Build and install #{name}-#{version}.gem into system gems." - task "install" => "build" do - install_gem(built_gem_path) - end - - desc "Build and install #{name}-#{version}.gem into system gems without network access." - task "install:local" => "build" do - install_gem(built_gem_path, :local) - end - - 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`" - task "release", [:remote] => ["build", "release:guard_clean", - "release:source_control_push", "release:rubygem_push"] do - end - - task "release:guard_clean" do - guard_clean - end - - task "release:source_control_push", [:remote] do |_, args| - tag_version { git_push(args[:remote]) } unless already_tagged? - end - - task "release:rubygem_push" do - rubygem_push(built_gem_path) if gem_push? - end - - GemHelper.instance = self - end - - def build_gem - file_name = nil - sh("gem build -V '#{spec_path}'") do - file_name = File.basename(built_gem_path) - SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } - FileUtils.mv(built_gem_path, "pkg") - Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." - end - File.join(base, "pkg", file_name) - end - - def install_gem(built_gem_path = nil, local = false) - built_gem_path ||= build_gem - out, _ = sh_with_code("gem install '#{built_gem_path}'#{" --local" if local}") - raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/] - Bundler.ui.confirm "#{name} (#{version}) installed." - end - - protected - - def rubygem_push(path) - gem_command = "gem push '#{path}'" - gem_command += " --key #{gem_key}" if gem_key - gem_command += " --host #{allowed_push_host}" if allowed_push_host - 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." - end - sh(gem_command) - Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" - end - - def built_gem_path - Dir[File.join(base, "#{name}-*.gem")].sort_by {|f| File.mtime(f) }.last - end - - def git_push(remote = "") - perform_git_push remote - perform_git_push "#{remote} --tags" - Bundler.ui.confirm "Pushed git commits and tags." - 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 = "") - cmd = "git push #{options}" - out, code = sh_with_code(cmd) - raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0 - end - - def already_tagged? - return false unless sh("git tag").split(/\n/).include?(version_tag) - Bundler.ui.confirm "Tag #{version_tag} has already been created." - true - end - - def guard_clean - clean? && committed? || raise("There are files that need to be committed first.") - end - - def clean? - sh_with_code("git diff --exit-code")[1] == 0 - end - - def committed? - sh_with_code("git diff-index --quiet --cached HEAD")[1] == 0 - end - - def tag_version - sh "git tag -m \"Version #{version}\" #{version_tag}" - Bundler.ui.confirm "Tagged #{version_tag}." - yield if block_given? - rescue - Bundler.ui.error "Untagging #{version_tag} due to error." - sh_with_code "git tag -d #{version_tag}" - raise - end - - def version - gemspec.version - end - - def version_tag - "v#{version}" - end - - def name - gemspec.name - end - - def sh(cmd, &block) - out, code = sh_with_code(cmd, &block) - unless code.zero? - raise(out.empty? ? "Running `#{cmd}` failed. Run this command directly for more detailed output." : out) - end - out - end - - def sh_with_code(cmd, &block) - cmd += " 2>&1" - outbuf = String.new - Bundler.ui.debug(cmd) - SharedHelpers.chdir(base) do - outbuf = `#{cmd}` - status = $?.exitstatus - block.call(outbuf) if status.zero? && block - [outbuf, status] - end - end - - def gem_key - Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] - end - - def gem_push? - !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) - end - end -end diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb deleted file mode 100644 index 019ae10c66..0000000000 --- a/lib/bundler/gem_helpers.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module GemHelpers - GENERIC_CACHE = {} # rubocop:disable MutableConstant - GENERICS = [ - [Gem::Platform.new("java"), Gem::Platform.new("java")], - [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], - [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], - [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], - [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")], - [Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")], - [Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")] - ].freeze - - def generic(p) - return p if p == Gem::Platform::RUBY - - GENERIC_CACHE[p] ||= begin - _, found = GENERICS.find do |match, _generic| - p.os == match.os && (!match.cpu || p.cpu == match.cpu) - end - found || Gem::Platform::RUBY - end - end - module_function :generic - - def generic_local_platform - generic(Bundler.local_platform) - end - module_function :generic_local_platform - - def platform_specificity_match(spec_platform, user_platform) - spec_platform = Gem::Platform.new(spec_platform) - return PlatformMatch::EXACT_MATCH if spec_platform == user_platform - return PlatformMatch::WORST_MATCH if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY - - PlatformMatch.new( - PlatformMatch.os_match(spec_platform, user_platform), - PlatformMatch.cpu_match(spec_platform, user_platform), - PlatformMatch.platform_version_match(spec_platform, user_platform) - ) - end - module_function :platform_specificity_match - - def select_best_platform_match(specs, platform) - specs.select {|spec| spec.match_platform(platform) }. - min_by {|spec| platform_specificity_match(spec.platform, platform) } - end - module_function :select_best_platform_match - - PlatformMatch = Struct.new(:os_match, :cpu_match, :platform_version_match) - class PlatformMatch - def <=>(other) - return nil unless other.is_a?(PlatformMatch) - - m = os_match <=> other.os_match - return m unless m.zero? - - m = cpu_match <=> other.cpu_match - return m unless m.zero? - - m = platform_version_match <=> other.platform_version_match - m - end - - EXACT_MATCH = new(-1, -1, -1).freeze - WORST_MATCH = new(1_000_000, 1_000_000, 1_000_000).freeze - - def self.os_match(spec_platform, user_platform) - if spec_platform.os == user_platform.os - 0 - else - 1 - end - end - - def self.cpu_match(spec_platform, user_platform) - if spec_platform.cpu == user_platform.cpu - 0 - elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") - 0 - elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" - 1 - else - 2 - end - end - - def self.platform_version_match(spec_platform, user_platform) - if spec_platform.version == user_platform.version - 0 - elsif spec_platform.version.nil? - 1 - else - 2 - end - end - end - end -end diff --git a/lib/bundler/gem_remote_fetcher.rb b/lib/bundler/gem_remote_fetcher.rb deleted file mode 100644 index 9577535d63..0000000000 --- a/lib/bundler/gem_remote_fetcher.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/remote_fetcher" - -module Bundler - # Adds support for setting custom HTTP headers when fetching gems from the - # server. - # - # TODO: Get rid of this when and if gemstash only supports RubyGems versions - # that contain https://github.com/rubygems/rubygems/commit/3db265cc20b2f813. - class GemRemoteFetcher < Gem::RemoteFetcher - attr_accessor :headers - - # Extracted from RubyGems 2.4. - def fetch_http(uri, last_modified = nil, head = false, depth = 0) - fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get - # beginning of change - response = request uri, fetch_type, last_modified do |req| - headers.each {|k, v| req.add_field(k, v) } if headers - end - # end of change - - case response - when Net::HTTPOK, Net::HTTPNotModified then - response.uri = uri if response.respond_to? :uri - head ? response : response.body - when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, - Net::HTTPTemporaryRedirect then - raise FetchError.new("too many redirects", uri) if depth > 10 - - location = URI.parse response["Location"] - - if https?(uri) && !https?(location) - raise FetchError.new("redirecting to non-https resource: #{location}", uri) - end - - fetch_http(location, last_modified, head, depth + 1) - else - raise FetchError.new("bad response #{response.message} #{response.code}", uri) - end - end - end -end diff --git a/lib/bundler/gem_tasks.rb b/lib/bundler/gem_tasks.rb deleted file mode 100644 index f736517bd7..0000000000 --- a/lib/bundler/gem_tasks.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require "rake/clean" -CLOBBER.include "pkg" - -require "bundler/gem_helper" -Bundler::GemHelper.install_tasks diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb deleted file mode 100644 index 52b5386045..0000000000 --- a/lib/bundler/gem_version_promoter.rb +++ /dev/null @@ -1,176 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # 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). - # Primarily designed to work with Resolver which will provide it the list of - # available dependency versions as found in its index, before returning it to - # to the resolution engine to select the best version. - class GemVersionPromoter - attr_reader :level, :locked_specs, :unlock_gems - - # By default, strict is false, meaning every available version of a gem - # is returned from sort_versions. The order gives preference to the - # requested level (:patch, :minor, :major) but in complicated requirement - # cases some gems will by necessity by promoted past the requested level, - # or even reverted to older versions. - # - # If strict is set to true, the results from sort_versions will be - # truncated, eliminating any version outside the current level scope. - # This can lead to unexpected outcomes or even VersionConflict exceptions - # that report a version of a gem not existing for versions that indeed do - # existing in the referenced source. - attr_accessor :strict - - # Given a list of locked_specs and a list of gems to unlock creates a - # GemVersionPromoter instance. - # - # @param locked_specs [SpecSet] All current locked specs. Unlike Definition - # where this list is empty if all gems are being updated, this should - # always be populated for all gems so this class can properly function. - # @param unlock_gems [String] List of gem names being unlocked. If empty, - # all gems will be considered unlocked. - # @return [GemVersionPromoter] - def initialize(locked_specs = SpecSet.new([]), unlock_gems = []) - @level = :major - @strict = false - @locked_specs = locked_specs - @unlock_gems = unlock_gems - @sort_versions = {} - end - - # @param value [Symbol] One of three Symbols: :major, :minor or :patch. - def level=(value) - v = case value - when String, Symbol - value.to_sym - end - - raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) - @level = v - end - - # Given a Dependency and an Array of SpecGroups of available versions for a - # gem, this method will return the Array of SpecGroups sorted (and possibly - # truncated if strict is true) in an order to give preference to the current - # level (:major, :minor or :patch) when resolution is deciding what versions - # best resolve all dependencies in the bundle. - # @param dep [Dependency] The Dependency of the gem. - # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem - # named in the @dep param. - # @return [SpecGroup] A new instance of the SpecGroup Array sorted and - # possibly filtered. - def sort_versions(dep, spec_groups) - before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if ENV["DEBUG_RESOLVER"] - - @sort_versions[dep] ||= begin - gem_name = dep.name - - # An Array per version returned, different entries for different platforms. - # We only need the version here so it's ok to hard code this to the first instance. - locked_spec = locked_specs[gem_name].first - - if strict - filter_dep_specs(spec_groups, locked_spec) - else - sort_dep_specs(spec_groups, locked_spec) - end.tap do |specs| - if ENV["DEBUG_RESOLVER"] - STDERR.puts before_result - STDERR.puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" - end - end - end - end - - # @return [bool] Convenience method for testing value of level variable. - def major? - level == :major - end - - # @return [bool] Convenience method for testing value of level variable. - def minor? - level == :minor - end - - private - - def filter_dep_specs(spec_groups, locked_spec) - res = spec_groups.select do |spec_group| - if locked_spec && !major? - gsv = spec_group.version - lsv = locked_spec.version - - must_match = minor? ? [0] : [0, 1] - - matches = must_match.map {|idx| gsv.segments[idx] == lsv.segments[idx] } - (matches.uniq == [true]) ? (gsv >= lsv) : false - else - true - end - end - - sort_dep_specs(res, locked_spec) - end - - def sort_dep_specs(spec_groups, locked_spec) - return spec_groups unless locked_spec - @gem_name = locked_spec.name - @locked_version = locked_spec.version - - result = spec_groups.sort do |a, b| - @a_ver = a.version - @b_ver = b.version - if major? - @a_ver <=> @b_ver - elsif either_version_older_than_locked - @a_ver <=> @b_ver - elsif segments_do_not_match(:major) - @b_ver <=> @a_ver - elsif !minor? && segments_do_not_match(:minor) - @b_ver <=> @a_ver - else - @a_ver <=> @b_ver - end - end - post_sort(result) - end - - def either_version_older_than_locked - @a_ver < @locked_version || @b_ver < @locked_version - end - - def segments_do_not_match(level) - index = [:major, :minor].index(level) - @a_ver.segments[index] != @b_ver.segments[index] - end - - def unlocking_gem? - unlock_gems.empty? || unlock_gems.include?(@gem_name) - end - - # Specific version moves can't always reliably be done during sorting - # as not all elements are compared against each other. - def post_sort(result) - # default :major behavior in Bundler does not do this - return result if major? - if unlocking_gem? - result - else - move_version_to_end(result, @locked_version) - end - end - - def move_version_to_end(result, version) - move, keep = result.partition {|s| s.version.to_s == version.to_s } - keep.concat(move) - end - - def debug_format_result(dep, spec_groups) - a = [dep.to_s, - spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] - last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } - [a.first, last_map, level, strict ? :strict : :not_strict] - end - end -end diff --git a/lib/bundler/gemdeps.rb b/lib/bundler/gemdeps.rb deleted file mode 100644 index cd4b25d0e6..0000000000 --- a/lib/bundler/gemdeps.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Gemdeps - def initialize(runtime) - @runtime = runtime - end - - def requested_specs - @runtime.requested_specs - end - - def specs - @runtime.specs - end - - def dependencies - @runtime.dependencies - end - - def current_dependencies - @runtime.current_dependencies - end - - def requires - @runtime.requires - end - end -end diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb deleted file mode 100644 index de6bba0214..0000000000 --- a/lib/bundler/graph.rb +++ /dev/null @@ -1,152 +0,0 @@ -# frozen_string_literal: true - -require "set" -module Bundler - class Graph - GRAPH_NAME = :Gemfile - - def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = []) - @env = env - @output_file = output_file - @show_version = show_version - @show_requirements = show_requirements - @output_format = output_format - @without_groups = without.map(&:to_sym) - - @groups = [] - @relations = Hash.new {|h, k| h[k] = Set.new } - @node_options = {} - @edge_options = {} - - _populate_relations - end - - attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format - - def viz - GraphVizClient.new(self).run - end - - private - - def _populate_relations - parent_dependencies = _groups.values.to_set.flatten - loop do - break if parent_dependencies.empty? - - tmp = Set.new - parent_dependencies.each do |dependency| - child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set - @relations[dependency.name] += child_dependencies.map(&:name).to_set - tmp += child_dependencies - - @node_options[dependency.name] = _make_label(dependency, :node) - child_dependencies.each do |c_dependency| - @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge) - end - end - parent_dependencies = tmp - end - end - - def _groups - relations = Hash.new {|h, k| h[k] = Set.new } - @env.current_dependencies.each do |dependency| - dependency.groups.each do |group| - next if @without_groups.include?(group) - - relations[group.to_s].add(dependency) - @relations[group.to_s].add(dependency.name) - - @node_options[group.to_s] ||= _make_label(group, :node) - @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge) - end - end - @groups = relations.keys - relations - end - - def _make_label(symbol_or_string_or_dependency, element_type) - case element_type.to_sym - when :node - if symbol_or_string_or_dependency.is_a?(Gem::Dependency) - label = symbol_or_string_or_dependency.name.dup - label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version - else - label = symbol_or_string_or_dependency.to_s - end - when :edge - label = nil - if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements - tmp = symbol_or_string_or_dependency.requirements_list.join(", ") - label = tmp if tmp != ">= 0" - end - else - raise ArgumentError, "2nd argument is invalid" - end - label.nil? ? {} : { :label => label } - end - - def spec_for_dependency(dependency) - @env.requested_specs.find {|s| s.name == dependency.name } - end - - class GraphVizClient - def initialize(graph_instance) - @graph_name = graph_instance.class::GRAPH_NAME - @groups = graph_instance.groups - @relations = graph_instance.relations - @node_options = graph_instance.node_options - @edge_options = graph_instance.edge_options - @output_file = graph_instance.output_file - @output_format = graph_instance.output_format - end - - def g - @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g| - g.edge[:weight] = 2 - g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif" - g.edge[:fontsize] = 12 - end - end - - def run - @groups.each do |group| - g.add_nodes( - group, { - :style => "filled", - :fillcolor => "#B9B9D5", - :shape => "box3d", - :fontsize => 16 - }.merge(@node_options[group]) - ) - end - - @relations.each do |parent, children| - children.each do |child| - if @groups.include?(parent) - g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child])) - g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"])) - else - g.add_nodes(child, @node_options[child]) - g.add_edges(parent, child, @edge_options["#{parent}_#{child}"]) - end - end - end - - if @output_format.to_s == "debug" - $stdout.puts g.output :none => String - Bundler.ui.info "debugging bundle viz..." - else - begin - g.output @output_format.to_sym => "#{@output_file}.#{@output_format}" - Bundler.ui.info "#{@output_file}.#{@output_format}" - rescue ArgumentError => e - $stderr.puts "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb" - raise e - end - end - end - end - end -end diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb deleted file mode 100644 index 9166a92738..0000000000 --- a/lib/bundler/index.rb +++ /dev/null @@ -1,213 +0,0 @@ -# frozen_string_literal: true - -require "set" - -module Bundler - class Index - include Enumerable - - def self.build - i = new - yield i - i - end - - attr_reader :specs, :all_specs, :sources - protected :specs, :all_specs - - RUBY = "ruby".freeze - NULL = "\0".freeze - - def initialize - @sources = [] - @cache = {} - @specs = Hash.new {|h, k| h[k] = {} } - @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } - end - - def initialize_copy(o) - @sources = o.sources.dup - @cache = {} - @specs = Hash.new {|h, k| h[k] = {} } - @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } - - o.specs.each do |name, hash| - @specs[name] = hash.dup - end - o.all_specs.each do |name, array| - @all_specs[name] = array.dup - end - end - - def inspect - "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" - end - - def empty? - each { return false } - true - end - - def search_all(name) - all_matches = local_search(name) + @all_specs[name] - @sources.each do |source| - all_matches.concat(source.search_all(name)) - end - all_matches - end - - # Search this index's specs, and any source indexes that this index knows - # about, returning all of the results. - def search(query, base = nil) - sort_specs(unsorted_search(query, base)) - end - - def unsorted_search(query, base) - results = local_search(query, base) - - seen = results.map(&:full_name).to_set unless @sources.empty? - - @sources.each do |source| - source.unsorted_search(query, base).each do |spec| - results << spec if seen.add?(spec.full_name) - end - end - - results - end - protected :unsorted_search - - def self.sort_specs(specs) - specs.sort_by do |s| - platform_string = s.platform.to_s - [s.version, platform_string == RUBY ? NULL : platform_string] - end - end - - def sort_specs(specs) - self.class.sort_specs(specs) - end - - def local_search(query, base = nil) - case query - when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) - when String then specs_by_name(query) - when Gem::Dependency then search_by_dependency(query, base) - when DepProxy then search_by_dependency(query.dep, base) - else - raise "You can't search for a #{query.inspect}." - end - end - - alias_method :[], :search - - def <<(spec) - @specs[spec.name][spec.full_name] = spec - spec - end - - def each(&blk) - return enum_for(:each) unless blk - specs.values.each do |spec_sets| - spec_sets.values.each(&blk) - end - sources.each {|s| s.each(&blk) } - self - end - - def spec_names - names = specs.keys + sources.map(&:spec_names) - names.uniq! - names - end - - # returns a list of the dependencies - def unmet_dependency_names - dependency_names.select do |name| - name != "bundler" && search(name).empty? - end - end - - def dependency_names - names = [] - each do |spec| - spec.dependencies.each do |dep| - next if dep.type == :development - names << dep.name - end - end - names.uniq - end - - def use(other, override_dupes = false) - return unless other - other.each do |s| - if (dupes = search_by_spec(s)) && !dupes.empty? - # safe to << since it's a new array when it has contents - @all_specs[s.name] = dupes << s - next unless override_dupes - end - self << s - end - self - end - - def size - @sources.inject(@specs.size) do |size, source| - size += source.size - end - end - - # Whether all the specs in self are in other - # TODO: rename to #include? - def ==(other) - all? do |spec| - other_spec = other[spec].first - other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source - end - end - - def dependencies_eql?(spec, other_spec) - deps = spec.dependencies.select {|d| d.type != :development } - other_deps = other_spec.dependencies.select {|d| d.type != :development } - Set.new(deps) == Set.new(other_deps) - end - - def add_source(index) - raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) - @sources << index - @sources.uniq! # need to use uniq! here instead of checking for the item before adding - end - - private - - def specs_by_name(name) - @specs[name].values - end - - def search_by_dependency(dependency, base = nil) - @cache[base || false] ||= {} - @cache[base || false][dependency] ||= begin - specs = specs_by_name(dependency.name) - specs += base if base - found = specs.select do |spec| - next true if spec.source.is_a?(Source::Gemspec) - if base # allow all platforms when searching from a lockfile - dependency.matches_spec?(spec) - else - dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) - end - end - - found - end - end - - EMPTY_SEARCH = [].freeze - - def search_by_spec(spec) - spec = @specs[spec.name][spec.full_name] - spec ? [spec] : EMPTY_SEARCH - end - end -end diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb deleted file mode 100644 index 7fe6a91ddd..0000000000 --- a/lib/bundler/injector.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Injector - def self.inject(new_deps, options = {}) - injector = new(new_deps, options) - injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) - end - - def initialize(new_deps, options = {}) - @new_deps = new_deps - @options = options - end - - def inject(gemfile_path, lockfile_path) - if Bundler.frozen? - # ensure the lock and Gemfile are synced - Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) - end - - # temporarily unfreeze - Bundler.settings.temporary(:deployment => false, :frozen => false) do - # evaluate the Gemfile we have now - builder = Dsl.new - builder.eval_gemfile(gemfile_path) - - # don't inject any gems that are already in the Gemfile - @new_deps -= builder.dependencies - - # add new deps to the end of the in-memory Gemfile - # 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? - - # resolve to see if the new deps broke anything - @definition = builder.to_definition(lockfile_path, {}) - @definition.resolve_remotely! - - # since nothing broke, we can add those gems to the gemfile - append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @new_deps.any? - - # since we resolved successfully, write out the lockfile - @definition.lock(Bundler.default_lockfile) - - # invalidate the cached Bundler.definition - Bundler.reset_paths! - - # return an array of the deps that we added - @new_deps - end - end - - private - - def conservative_version(spec) - version = spec.version - return ">= 0" if version.nil? - segments = version.segments - seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 - - prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease? - "~> #{segments[0..seg_end_index].join(".")}#{prerelease_suffix}" - end - - def build_gem_lines(conservative_versioning) - @new_deps.map do |d| - name = d.name.dump - - requirement = if conservative_versioning - ", \"#{conservative_version(@definition.specs[d.name][0])}\"" - else - ", #{d.requirement.as_list.map(&:dump).join(", ")}" - end - - if d.groups != Array(:default) - group = d.groups.size == 1 ? ", :group => #{d.groups.inspect}" : ", :groups => #{d.groups.inspect}" - end - - source = ", :source => \"#{d.source}\"" unless d.source.nil? - - %(gem #{name}#{requirement}#{group}#{source}) - end.join("\n") - end - - def append_to(gemfile_path, new_gem_lines) - gemfile_path.open("a") do |f| - f.puts - if @options["timestamp"] || @options["timestamp"].nil? - f.puts "# Added at #{Time.now} by #{`whoami`.chomp}:" - end - f.puts new_gem_lines - end - end - end -end diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb deleted file mode 100644 index 9d25f3261a..0000000000 --- a/lib/bundler/inline.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require "bundler/compatibility_guard" - -# Allows for declaring a Gemfile inline in a ruby script, optionally installing -# any gems that aren't already installed on the user's system. -# -# @note Every gem that is specified in this 'Gemfile' will be `require`d, as if -# the user had manually called `Bundler.require`. To avoid a requested gem -# being automatically required, add the `:require => false` option to the -# `gem` dependency declaration. -# -# @param install [Boolean] whether gems that aren't already installed on the -# user's system should be installed. -# Defaults to `false`. -# -# @param gemfile [Proc] a block that is evaluated as a `Gemfile`. -# -# @example Using an inline Gemfile -# -# #!/usr/bin/env ruby -# -# require 'bundler/inline' -# -# gemfile do -# source 'https://rubygems.org' -# gem 'json', require: false -# gem 'nap', require: 'rest' -# gem 'cocoapods', '~> 0.34.1' -# end -# -# puts Pod::VERSION # => "0.34.4" -# -def gemfile(install = false, options = {}, &gemfile) - require "bundler" - - opts = options.dup - ui = opts.delete(:ui) { Bundler::UI::Shell.new } - raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? - - old_root = Bundler.method(:root) - def Bundler.root - Bundler::SharedHelpers.pwd.expand_path - end - Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" - - Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? - builder = Bundler::Dsl.new - builder.instance_eval(&gemfile) - - definition = builder.to_definition(nil, true) - def definition.lock(*); end - definition.validate_runtime! - - missing_specs = proc do - definition.missing_specs? - end - - Bundler.ui = ui if install - if install || missing_specs.call - Bundler.settings.temporary(:inline => true) do - installer = Bundler::Installer.install(Bundler.root, definition, :system => true) - installer.post_install_messages.each do |name, message| - Bundler.ui.info "Post-install message from #{name}:\n#{message}" - end - end - end - - runtime = Bundler::Runtime.new(nil, definition) - runtime.setup.require -ensure - bundler_module = class << Bundler; self; end - bundler_module.send(:define_method, :root, old_root) if old_root -end diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb deleted file mode 100644 index d1066c9c19..0000000000 --- a/lib/bundler/installer.rb +++ /dev/null @@ -1,287 +0,0 @@ -# frozen_string_literal: true - -require "erb" -require "rubygems/dependency_installer" -require "bundler/worker" -require "bundler/installer/parallel_installer" -require "bundler/installer/standalone" -require "bundler/installer/gem_installer" - -module Bundler - class Installer - class << self - attr_accessor :ambiguous_gems - - Installer.ambiguous_gems = [] - end - - attr_reader :post_install_messages - - # Begins the installation process for Bundler. - # For more information see the #run method on this class. - def self.install(root, definition, options = {}) - installer = new(root, definition) - Plugin.hook("before-install-all", definition.dependencies) - installer.run(options) - installer - end - - def initialize(root, definition) - @root = root - @definition = definition - @post_install_messages = {} - end - - # Runs the install procedures for a specific Gemfile. - # - # Firstly, this method will check to see if `Bundler.bundle_path` exists - # and if not then Bundler will create the directory. This is usually the same - # location as RubyGems which typically is the `~/.gem` directory - # unless other specified. - # - # Secondly, it checks if Bundler has been configured to be "frozen". - # 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 - # `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 - # `bundle install` will potentially not install the correct gems. - # - # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. - # If there are no dependencies specified then Bundler returns a warning message stating - # so and this method returns. - # - # Fourthly, Bundler checks if the Gemfile.lock exists, and if so - # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. - # During this step Bundler will also download information about any new 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. - # This then leads into the gems being installed, along with stubs for their executables, - # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set - # earlier. - # - # 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. - # - # 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) - create_bundle_path - - ProcessLock.lock do - if Bundler.frozen? - @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) - end - - if @definition.dependencies.empty? - Bundler.ui.warn "The Gemfile specifies no dependencies" - lock - return - end - - if resolve_if_needed(options) - 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) - - lock unless Bundler.frozen? - Standalone.new(options[:standalone], @definition).generate if options[:standalone] - end - end - - def generate_bundler_executable_stubs(spec, options = {}) - if options[:binstubs_cmd] && spec.executables.empty? - options = {} - spec.runtime_dependencies.each do |dep| - bins = @definition.specs[dep].first.executables - options[dep.name] = bins unless bins.empty? - end - if options.any? - Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ - "one from a gem it depends on." - options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } - else - Bundler.ui.warn "There are no executables for the gem #{spec.name}." - end - return - end - - # double-assignment to avoid warnings about variables that will be used by ERB - bin_path = Bundler.bin_path - bin_path = bin_path - relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) - 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 = [] - spec.executables.each do |executable| - binstub_path = "#{bin_path}/#{executable}" - if File.exist?(binstub_path) && !options[:force] - exists << executable - next - end - - File.open(binstub_path, "w", 0o777 & ~File.umask) do |f| - f.puts ERB.new(template, nil, "-").result(binding) - end - end - - if options[:binstubs_cmd] && exists.any? - case exists.size - when 1 - Bundler.ui.warn "Skipped #{exists[0]} since it already exists." - when 2 - Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." - else - items = exists[0...-1].empty? ? |