├── .rspec ├── lib └── bundler │ ├── ssl_certs │ ├── .document │ ├── index.rubygems.org │ │ └── GlobalSignRootCA.pem │ ├── rubygems.global.ssl.fastly.net │ │ └── DigiCertHighAssuranceEVRootCA.pem │ ├── rubygems.org │ │ └── AddTrustExternalCARoot.pem │ └── certificate_manager.rb │ ├── templates │ ├── newgem │ │ ├── rspec.tt │ │ ├── exe │ │ │ └── newgem.tt │ │ ├── ext │ │ │ └── newgem │ │ │ │ ├── extconf.rb.tt │ │ │ │ ├── newgem.h.tt │ │ │ │ └── newgem.c.tt │ │ ├── Gemfile.tt │ │ ├── .travis.yml.tt │ │ ├── test │ │ │ ├── test_helper.rb.tt │ │ │ └── newgem_test.rb.tt │ │ ├── bin │ │ │ ├── setup.tt │ │ │ └── console.tt │ │ ├── lib │ │ │ ├── newgem │ │ │ │ └── version.rb.tt │ │ │ └── newgem.rb.tt │ │ ├── spec │ │ │ ├── newgem_spec.rb.tt │ │ │ └── spec_helper.rb.tt │ │ ├── gitignore.tt │ │ ├── Rakefile.tt │ │ ├── LICENSE.txt.tt │ │ └── newgem.gemspec.tt │ ├── Gemfile │ ├── Executable.standalone │ └── Executable │ ├── vendor │ ├── thor │ │ └── lib │ │ │ └── thor │ │ │ ├── version.rb │ │ │ ├── parser.rb │ │ │ ├── core_ext │ │ │ └── io_binary_read.rb │ │ │ ├── line_editor.rb │ │ │ ├── line_editor │ │ │ └── basic.rb │ │ │ ├── error.rb │ │ │ ├── actions │ │ │ └── create_link.rb │ │ │ └── parser │ │ │ └── argument.rb │ ├── postit │ │ └── lib │ │ │ ├── postit │ │ │ ├── version.rb │ │ │ ├── setup.rb │ │ │ ├── parser.rb │ │ │ ├── installer.rb │ │ │ └── environment.rb │ │ │ └── postit.rb │ ├── molinillo │ │ └── lib │ │ │ ├── molinillo │ │ │ ├── gem_metadata.rb │ │ │ ├── dependency_graph │ │ │ │ ├── tag.rb │ │ │ │ ├── action.rb │ │ │ │ ├── set_payload.rb │ │ │ │ ├── detach_vertex_named.rb │ │ │ │ └── add_vertex.rb │ │ │ ├── resolver.rb │ │ │ ├── delegates │ │ │ │ └── resolution_state.rb │ │ │ ├── state.rb │ │ │ └── modules │ │ │ │ └── ui.rb │ │ │ └── molinillo.rb │ └── net-http-persistent │ │ └── lib │ │ └── net │ │ └── http │ │ └── faster.rb │ ├── vendored_molinillo.rb │ ├── vendored_thor.rb │ ├── gem_tasks.rb │ ├── ui.rb │ ├── constants.rb │ ├── source │ ├── gemspec.rb │ └── rubygems │ │ └── remote.rb │ ├── ui │ ├── rg_proxy.rb │ └── silent.rb │ ├── vlad.rb │ ├── vendored_persistent.rb │ ├── gemdeps.rb │ ├── plugin │ ├── installer │ │ ├── rubygems.rb │ │ └── git.rb │ ├── source_list.rb │ └── dsl.rb │ ├── deprecate.rb │ ├── cli │ ├── clean.rb │ ├── open.rb │ ├── add.rb │ ├── viz.rb │ ├── init.rb │ ├── plugin.rb │ ├── pristine.rb │ ├── cache.rb │ ├── console.rb │ ├── binstubs.rb │ ├── issue.rb │ ├── check.rb │ ├── platform.rb │ ├── package.rb │ ├── info.rb │ └── lock.rb │ ├── match_platform.rb │ ├── capistrano.rb │ ├── psyched_yaml.rb │ ├── version.rb │ ├── ruby_dsl.rb │ ├── dep_proxy.rb │ ├── setup.rb │ ├── environment_preserver.rb │ ├── feature_flag.rb │ ├── fetcher │ ├── base.rb │ └── index.rb │ ├── uri_credentials_filter.rb │ ├── gem_remote_fetcher.rb │ ├── retry.rb │ ├── source.rb │ ├── installer │ └── standalone.rb │ └── similarity_detector.rb ├── exe ├── bundler ├── bundle └── bundle_ruby ├── spec ├── support │ ├── permissions.rb │ ├── silent_logger.rb │ ├── artifice │ │ ├── compact_index_forbidden.rb │ │ ├── endpoint_api_forbidden.rb │ │ ├── endpoint_marshal_fail.rb │ │ ├── endpoint_timeout.rb │ │ ├── endpoint_basic_authentication.rb │ │ ├── endpoint_redirect.rb │ │ ├── compact_index_basic_authentication.rb │ │ ├── endpoint_mirror_source.rb │ │ ├── endopint_marshal_fail_basic_authentication.rb │ │ ├── endpoint_500.rb │ │ ├── endpoint_extra_missing.rb │ │ ├── endpoint_host_redirect.rb │ │ ├── endpoint_api_missing.rb │ │ ├── compact_index_checksum_mismatch.rb │ │ ├── compact_index_redirects.rb │ │ ├── compact_index_extra_missing.rb │ │ ├── compact_index_api_missing.rb │ │ ├── compact_index_wrong_dependencies.rb │ │ ├── compact_index_host_redirect.rb │ │ ├── endpoint_fallback.rb │ │ ├── endpoint_strict_basic_authentication.rb │ │ ├── compact_index_strict_basic_authentication.rb │ │ ├── compact_index_wrong_gem_checksum.rb │ │ ├── endpoint_extra.rb │ │ ├── endpoint_extra_api.rb │ │ ├── compact_index_extra.rb │ │ ├── endpoint_creds_diff_host.rb │ │ ├── compact_index_creds_diff_host.rb │ │ ├── fail.rb │ │ ├── compact_index_concurrent_download.rb │ │ ├── windows.rb │ │ └── compact_index_extra_api.rb │ ├── streams.rb │ ├── sudo.rb │ ├── less_than_proc.rb │ ├── code_climate.rb │ ├── the_bundle.rb │ ├── hax.rb │ └── sometimes.rb ├── bundler │ ├── psyched_yaml_spec.rb │ ├── worker_spec.rb │ ├── plugin │ │ ├── source_list_spec.rb │ │ └── dsl_spec.rb │ ├── source │ │ └── rubygems_spec.rb │ ├── spec_set_spec.rb │ ├── compact_index_client │ │ └── updater_spec.rb │ ├── index_spec.rb │ ├── installer │ │ ├── gem_installer_spec.rb │ │ └── parallel_installer_spec.rb │ ├── ui_spec.rb │ └── version_ranges_spec.rb ├── commands │ ├── issue_spec.rb │ ├── licenses_spec.rb │ ├── init_spec.rb │ └── info_spec.rb ├── other │ ├── ssl_cert_spec.rb │ └── cli_dispatch_spec.rb ├── update │ └── path_spec.rb ├── install │ ├── gems │ │ ├── win32_spec.rb │ │ └── mirror_spec.rb │ ├── failure_spec.rb │ ├── force_spec.rb │ ├── gemfile │ │ ├── install_if.rb │ │ └── eval_gemfile_spec.rb │ ├── prereleases_spec.rb │ ├── git_spec.rb │ └── binstubs_spec.rb ├── plugins │ └── hook_spec.rb ├── lock │ └── git_spec.rb ├── cache │ ├── cache_path_spec.rb │ └── platform_spec.rb ├── runtime │ └── gem_tasks_spec.rb └── realworld │ ├── dependency_api_spec.rb │ └── gemfile_source_header_spec.rb ├── man ├── bundle-info.ronn ├── bundle-open.ronn ├── bundle-clean.ronn ├── index.txt ├── bundle-init.ronn ├── bundle-show.ronn ├── bundle-inject.ronn ├── bundle-check.ronn ├── bundle-binstubs.ronn ├── bundle-viz.ronn └── bundle-platform.ronn ├── bin ├── rspec ├── rubocop ├── rake └── with_rubygems ├── .codeclimate.yml ├── .gitignore ├── doc ├── development │ ├── RELEASING.md │ ├── NEW_FEATURES.md │ ├── README.md │ ├── SETUP.md │ └── PULL_REQUESTS.md ├── contributing │ ├── GETTING_HELP.md │ ├── COMMUNITY.md │ └── README.md ├── documentation │ ├── VISION.md │ └── README.md └── README.md ├── CONTRIBUTING.md ├── LICENSE.md └── bundler.gemspec /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --warnings 4 | -------------------------------------------------------------------------------- /lib/bundler/ssl_certs/.document: -------------------------------------------------------------------------------- 1 | # Ignore all files in this directory 2 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/rspec.tt: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/version.rb: -------------------------------------------------------------------------------- 1 | class Bundler::Thor 2 | VERSION = "0.19.4" 3 | end 4 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/exe/newgem.tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "<%= config[:namespaced_path] %>" 4 | -------------------------------------------------------------------------------- /exe/bundler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | load File.expand_path("../bundle", __FILE__) 5 | -------------------------------------------------------------------------------- /lib/bundler/templates/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | 4 | # gem "rails" 5 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit/version.rb: -------------------------------------------------------------------------------- 1 | module BundlerVendoredPostIt::PostIt 2 | VERSION = '0.2.0'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt: -------------------------------------------------------------------------------- 1 | require "mkmf" 2 | 3 | create_makefile(<%= config[:makefile_path].inspect %>) 4 | -------------------------------------------------------------------------------- /lib/bundler/vendored_molinillo.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler; end 3 | require "bundler/vendor/molinillo/lib/molinillo" 4 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/Gemfile.tt: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in <%= config[:name] %>.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/.travis.yml.tt: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - <%= RUBY_VERSION %> 5 | before_install: gem install bundler -v <%= Bundler::VERSION %> 6 | -------------------------------------------------------------------------------- /lib/bundler/vendored_thor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler; end 3 | require "bundler/vendor/thor/lib/thor" 4 | require "bundler/vendor/thor/lib/thor/actions" 5 | -------------------------------------------------------------------------------- /lib/bundler/gem_tasks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rake/clean" 3 | CLOBBER.include "pkg" 4 | 5 | require "bundler/gem_helper" 6 | Bundler::GemHelper.install_tasks 7 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/test/test_helper.rb.tt: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) 2 | require "<%= config[:namespaced_path] %>" 3 | 4 | require "minitest/autorun" 5 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/bin/setup.tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler::Molinillo 3 | # The version of Bundler::Molinillo. 4 | VERSION = '0.5.7'.freeze 5 | end 6 | -------------------------------------------------------------------------------- /lib/bundler/ui.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | module UI 4 | autoload :RGProxy, "bundler/ui/rg_proxy" 5 | autoload :Shell, "bundler/ui/shell" 6 | autoload :Silent, "bundler/ui/silent" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/ext/newgem/newgem.h.tt: -------------------------------------------------------------------------------- 1 | #ifndef <%= config[:underscored_name].upcase %>_H 2 | #define <%= config[:underscored_name].upcase %>_H 1 3 | 4 | #include "ruby.h" 5 | 6 | #endif /* <%= config[:underscored_name].upcase %>_H */ 7 | -------------------------------------------------------------------------------- /lib/bundler/constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ 4 | FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ 5 | NULL = WINDOWS ? "NUL" : "/dev/null" 6 | end 7 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/parser.rb: -------------------------------------------------------------------------------- 1 | require "bundler/vendor/thor/lib/thor/parser/argument" 2 | require "bundler/vendor/thor/lib/thor/parser/arguments" 3 | require "bundler/vendor/thor/lib/thor/parser/option" 4 | require "bundler/vendor/thor/lib/thor/parser/options" 5 | -------------------------------------------------------------------------------- /spec/support/permissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Spec 3 | module Permissions 4 | def with_umask(new_umask) 5 | old_umask = File.umask(new_umask) 6 | yield if block_given? 7 | ensure 8 | File.umask(old_umask) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/silent_logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "logger" 3 | module Spec 4 | class SilentLogger 5 | (::Logger.instance_methods - Object.instance_methods).each do |logger_instance_method| 6 | define_method(logger_instance_method) {|*args, &blk| } 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/lib/newgem/version.rb.tt: -------------------------------------------------------------------------------- 1 | <%- config[:constant_array].each_with_index do |c, i| -%> 2 | <%= " " * i %>module <%= c %> 3 | <%- end -%> 4 | <%= " " * config[:constant_array].size %>VERSION = "0.1.0" 5 | <%- (config[:constant_array].size-1).downto(0) do |i| -%> 6 | <%= " " * i %>end 7 | <%- end -%> 8 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/ext/newgem/newgem.c.tt: -------------------------------------------------------------------------------- 1 | #include "<%= config[:underscored_name] %>.h" 2 | 3 | VALUE rb_m<%= config[:constant_array].join %>; 4 | 5 | void 6 | Init_<%= config[:underscored_name] %>(void) 7 | { 8 | rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); 9 | } 10 | -------------------------------------------------------------------------------- /spec/bundler/psyched_yaml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/psyched_yaml" 4 | 5 | RSpec.describe "Bundler::YamlLibrarySyntaxError" do 6 | it "is raised on YAML parse errors" do 7 | expect { YAML.parse "{foo" }.to raise_error(Bundler::YamlLibrarySyntaxError) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/spec/newgem_spec.rb.tt: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe <%= config[:constant_name] %> do 4 | it "has a version number" do 5 | expect(<%= config[:constant_name] %>::VERSION).not_to be nil 6 | end 7 | 8 | it "does something useful" do 9 | expect(false).to eq(true) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/test/newgem_test.rb.tt: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class <%= config[:constant_name] %>Test < Minitest::Test 4 | def test_that_it_has_a_version_number 5 | refute_nil ::<%= config[:constant_name] %>::VERSION 6 | end 7 | 8 | def test_it_does_something_useful 9 | assert false 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_forbidden.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexForbidden < CompactIndexAPI 7 | get "/versions" do 8 | halt 403 9 | end 10 | end 11 | 12 | Artifice.activate_with(CompactIndexForbidden) 13 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_api_forbidden.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointApiForbidden < Endpoint 7 | get "/api/v1/dependencies" do 8 | halt 403 9 | end 10 | end 11 | 12 | Artifice.activate_with(EndpointApiForbidden) 13 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_marshal_fail.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint_fallback", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointMarshalFail < EndpointFallback 7 | get "/api/v1/dependencies" do 8 | "f0283y01hasf" 9 | end 10 | end 11 | 12 | Artifice.activate_with(EndpointMarshalFail) 13 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/gitignore.tt: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | <%- if config[:ext] -%> 11 | *.bundle 12 | *.so 13 | *.o 14 | *.a 15 | mkmf.log 16 | <%- end -%> 17 | <%- if config[:test] == "rspec" -%> 18 | 19 | # rspec failure tracking 20 | .rspec_status 21 | <%- end -%> 22 | -------------------------------------------------------------------------------- /spec/support/streams.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "stringio" 3 | 4 | def capture(*streams) 5 | streams.map!(&:to_s) 6 | begin 7 | result = StringIO.new 8 | streams.each {|stream| eval "$#{stream} = result" } 9 | yield 10 | ensure 11 | streams.each {|stream| eval("$#{stream} = #{stream.upcase}") } 12 | end 13 | result.string 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_timeout.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint_fallback", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointTimeout < EndpointFallback 7 | SLEEP_TIMEOUT = 15 8 | 9 | get "/api/v1/dependencies" do 10 | sleep(SLEEP_TIMEOUT) 11 | end 12 | end 13 | 14 | Artifice.activate_with(EndpointTimeout) 15 | -------------------------------------------------------------------------------- /lib/bundler/source/gemspec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Source 4 | class Gemspec < Path 5 | attr_reader :gemspec 6 | 7 | def initialize(options) 8 | super 9 | @gemspec = options["gemspec"] 10 | end 11 | 12 | def as_path_source 13 | Path.new(options) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/bundler/ui/rg_proxy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/ui" 3 | require "rubygems/user_interaction" 4 | 5 | module Bundler 6 | module UI 7 | class RGProxy < ::Gem::SilentUI 8 | def initialize(ui) 9 | @ui = ui 10 | super() 11 | end 12 | 13 | def say(message) 14 | @ui && @ui.debug(message) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb: -------------------------------------------------------------------------------- 1 | class IO #:nodoc: 2 | class << self 3 | unless method_defined? :binread 4 | def binread(file, *args) 5 | raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3 6 | File.open(file, "rb") do |f| 7 | f.read(*args) 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/bundler/vlad.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Vlad task for Bundler. 3 | # 4 | # Add "require 'bundler/vlad'" in your Vlad deploy.rb, and 5 | # include the vlad:bundle:install task in your vlad:deploy task. 6 | require "bundler/deployment" 7 | 8 | include Rake::DSL if defined? Rake::DSL 9 | 10 | namespace :vlad do 11 | Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app) 12 | end 13 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointBasicAuthentication < Endpoint 7 | before do 8 | unless env["HTTP_AUTHORIZATION"] 9 | halt 401, "Authentication info not supplied" 10 | end 11 | end 12 | end 13 | 14 | Artifice.activate_with(EndpointBasicAuthentication) 15 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_redirect.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointRedirect < Endpoint 7 | get "/fetch/actual/gem/:id" do 8 | redirect "/fetch/actual/gem/#{params[:id]}" 9 | end 10 | 11 | get "/api/v1/dependencies" do 12 | status 404 13 | end 14 | end 15 | 16 | Artifice.activate_with(EndpointRedirect) 17 | -------------------------------------------------------------------------------- /spec/support/sudo.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Spec 3 | module Sudo 4 | def self.present? 5 | @which_sudo ||= Bundler.which("sudo") 6 | end 7 | 8 | def sudo(cmd) 9 | raise "sudo not present" unless Sudo.present? 10 | sys_exec("sudo #{cmd}") 11 | end 12 | 13 | def chown_system_gems_to_root 14 | sudo "chown -R root #{system_gem_path}" 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit/setup.rb: -------------------------------------------------------------------------------- 1 | require 'bundler/vendor/postit/lib/postit/environment' 2 | require 'bundler/vendor/postit/lib/postit/installer' 3 | 4 | environment = BundlerVendoredPostIt::PostIt::Environment.new(ARGV) 5 | version = environment.bundler_version 6 | 7 | installer = BundlerVendoredPostIt::PostIt::Installer.new(version) 8 | installer.install! 9 | 10 | gem 'bundler', version 11 | 12 | require 'bundler/version' 13 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexBasicAuthentication < CompactIndexAPI 7 | before do 8 | unless env["HTTP_AUTHORIZATION"] 9 | halt 401, "Authentication info not supplied" 10 | end 11 | end 12 | end 13 | 14 | Artifice.activate_with(CompactIndexBasicAuthentication) 15 | -------------------------------------------------------------------------------- /man/bundle-info.ronn: -------------------------------------------------------------------------------- 1 | bundle-info(1) -- Show information for the given gem in your bundle 2 | ========================================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle info` [GEM] 7 | [--path] 8 | 9 | ## DESCRIPTION 10 | 11 | Print the basic information about the provided GEM such as homepage, version, 12 | path and summary. 13 | 14 | ## OPTIONS 15 | 16 | * `--path`: 17 | Print the path of the given gem 18 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_mirror_source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | class EndpointMirrorSource < Endpoint 5 | get "/gems/:id" do 6 | if request.env["HTTP_X_GEMFILE_SOURCE"] == "https://server.example.org/" 7 | File.read("#{gem_repo1}/gems/#{params[:id]}") 8 | else 9 | halt 500 10 | end 11 | end 12 | end 13 | 14 | Artifice.activate_with(EndpointMirrorSource) 15 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/bin/console.tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "<%= config[:namespaced_path] %>" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | load File.expand_path("../with_rubygems", __FILE__) if ENV["RGV"] 5 | 6 | require "rubygems" 7 | 8 | bundler_spec = Gem::Specification.load(File.expand_path("../../bundler.gemspec", __FILE__)) 9 | bundler_spec.dependencies.each do |dep| 10 | gem dep.name, dep.requirement 11 | end 12 | 13 | Gem.finish_resolve if Gem.respond_to?(:finish_resolve) 14 | 15 | load Gem.bin_path("rspec-core", "rspec") 16 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - ruby 8 | fixme: 9 | enabled: true 10 | rubocop: 11 | enabled: false 12 | ratings: 13 | paths: 14 | - "**.rb" 15 | - "bin/*" 16 | - "exe/*" 17 | exclude_paths: 18 | - bundler.gemspec 19 | - "*.md" 20 | - lib/bundler/ssl_certs/*.pem 21 | - lib/bundler/vendor/**/* 22 | - lib/bundler/templates/**/*.tt 23 | - man/* 24 | - spec/**/* 25 | - Rakefile 26 | -------------------------------------------------------------------------------- /spec/support/artifice/endopint_marshal_fail_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint_marshal_fail", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointMarshalFailBasicAuthentication < EndpointMarshalFail 7 | before do 8 | unless env["HTTP_AUTHORIZATION"] 9 | halt 401, "Authentication info not supplied" 10 | end 11 | end 12 | end 13 | 14 | Artifice.activate_with(EndpointMarshalFailBasicAuthentication) 15 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/spec/spec_helper.rb.tt: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "<%= config[:namespaced_path] %>" 3 | 4 | RSpec.configure do |config| 5 | # Enable flags like --only-failures and --next-failure 6 | config.example_status_persistence_file_path = ".rspec_status" 7 | 8 | # Disable RSpec exposing methods globally on `Module` and `main` 9 | config.disable_monkey_patching! 10 | 11 | config.expect_with :rspec do |c| 12 | c.syntax = :expect 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_500.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../../path.rb", __FILE__) 3 | include Spec::Path 4 | 5 | $LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,rack,tilt,sinatra}-*/lib")].map(&:to_s)) 6 | 7 | require "artifice" 8 | require "sinatra/base" 9 | 10 | Artifice.deactivate 11 | 12 | class Endpoint500 < Sinatra::Base 13 | before do 14 | halt 500 15 | end 16 | end 17 | 18 | Artifice.activate_with(Endpoint500) 19 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_extra_missing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint_extra", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointExtraMissing < EndpointExtra 7 | get "/extra/fetch/actual/gem/:id" do 8 | if params[:id] == "missing-1.0.gemspec.rz" 9 | halt 404 10 | else 11 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 12 | end 13 | end 14 | end 15 | 16 | Artifice.activate_with(EndpointExtraMissing) 17 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_host_redirect.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointHostRedirect < Endpoint 7 | get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do 8 | redirect "http://bundler.localgemserver.test#{request.path_info}" 9 | end 10 | 11 | get "/api/v1/dependencies" do 12 | status 404 13 | end 14 | end 15 | 16 | Artifice.activate_with(EndpointHostRedirect) 17 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | load File.expand_path("../with_rubygems", __FILE__) if ENV["RGV"] 5 | 6 | require "rubygems" 7 | 8 | bundler_spec = Gem::Specification.load(File.expand_path("../../bundler.gemspec", __FILE__)) 9 | bundler_spec.dependencies.each do |dep| 10 | gem dep.name, dep.requirement 11 | end 12 | 13 | gem "rubocop", "= 0.48.0" 14 | 15 | Gem.finish_resolve if Gem.respond_to?(:finish_resolve) 16 | 17 | load Gem.bin_path("rubocop", "rubocop") 18 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/lib/newgem.rb.tt: -------------------------------------------------------------------------------- 1 | require "<%= config[:namespaced_path] %>/version" 2 | <%- if config[:ext] -%> 3 | require "<%= config[:namespaced_path] %>/<%= config[:underscored_name] %>" 4 | <%- end -%> 5 | 6 | <%- config[:constant_array].each_with_index do |c, i| -%> 7 | <%= " " * i %>module <%= c %> 8 | <%- end -%> 9 | <%= " " * config[:constant_array].size %># Your code goes here... 10 | <%- (config[:constant_array].size-1).downto(0) do |i| -%> 11 | <%= " " * i %>end 12 | <%- end -%> 13 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_api_missing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointApiMissing < Endpoint 7 | get "/fetch/actual/gem/:id" do 8 | $stderr.puts params[:id] 9 | if params[:id] == "rack-1.0.gemspec.rz" 10 | halt 404 11 | else 12 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 13 | end 14 | end 15 | end 16 | 17 | Artifice.activate_with(EndpointApiMissing) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Please do not submit patches for including directives to ignore IDE/editor 2 | # generated files. Use a global gitignore as described in 3 | # https://help.github.com/articles/ignoring-files and find useful gitignore 4 | # samples at https://github.com/github/gitignore 5 | 6 | # files created by running the specs 7 | /tmp/ 8 | 9 | # gems built by `rake build` 10 | /pkg/ 11 | 12 | # output from ronn 13 | /lib/bundler/man/ 14 | man/* 15 | !man/*.ronn 16 | 17 | # rspec failure tracking 18 | .rspec_status 19 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_checksum_mismatch.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexChecksumMismatch < CompactIndexAPI 7 | get "/versions" do 8 | headers "ETag" => quote("123") 9 | headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60" 10 | content_type "text/plain" 11 | body "" 12 | end 13 | end 14 | 15 | Artifice.activate_with(CompactIndexChecksumMismatch) 16 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_redirects.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexRedirect < CompactIndexAPI 7 | get "/fetch/actual/gem/:id" do 8 | redirect "/fetch/actual/gem/#{params[:id]}" 9 | end 10 | 11 | get "/versions" do 12 | status 404 13 | end 14 | 15 | get "/api/v1/dependencies" do 16 | status 404 17 | end 18 | end 19 | 20 | Artifice.activate_with(CompactIndexRedirect) 21 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/gem_metadata' 3 | require 'bundler/vendor/molinillo/lib/molinillo/errors' 4 | require 'bundler/vendor/molinillo/lib/molinillo/resolver' 5 | require 'bundler/vendor/molinillo/lib/molinillo/modules/ui' 6 | require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider' 7 | 8 | # Bundler::Molinillo is a generic dependency resolution algorithm. 9 | module Bundler::Molinillo 10 | end 11 | -------------------------------------------------------------------------------- /spec/commands/issue_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle issue" do 5 | it "exits with a message" do 6 | install_gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | gem "rails" 9 | G 10 | 11 | bundle "issue" 12 | expect(out).to include "Did you find an issue with Bundler?" 13 | expect(out).to include "## Environment" 14 | expect(out).to include "## Gemfile" 15 | expect(out).to include "## Bundle Doctor" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_extra_missing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index_extra", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexExtraMissing < CompactIndexExtra 7 | get "/extra/fetch/actual/gem/:id" do 8 | if params[:id] == "missing-1.0.gemspec.rz" 9 | halt 404 10 | else 11 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 12 | end 13 | end 14 | end 15 | 16 | Artifice.activate_with(CompactIndexExtraMissing) 17 | -------------------------------------------------------------------------------- /lib/bundler/vendored_persistent.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # We forcibly require OpenSSL, because net/http/persistent will only autoload 3 | # it. On some Rubies, autoload fails but explicit require succeeds. 4 | begin 5 | require "openssl" 6 | rescue LoadError 7 | # some Ruby builds don't have OpenSSL 8 | end 9 | module Bundler 10 | module Persistent 11 | module Net 12 | module HTTP 13 | end 14 | end 15 | end 16 | end 17 | require "bundler/vendor/net-http-persistent/lib/net/http/persistent" 18 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit.rb: -------------------------------------------------------------------------------- 1 | require 'bundler/vendor/postit/lib/postit/environment' 2 | require 'bundler/vendor/postit/lib/postit/installer' 3 | require 'bundler/vendor/postit/lib/postit/parser' 4 | require 'bundler/vendor/postit/lib/postit/version' 5 | require 'rubygems' 6 | 7 | module BundlerVendoredPostIt::PostIt 8 | def self.setup 9 | load File.expand_path('../postit/setup.rb', __FILE__) 10 | end 11 | 12 | def self.bundler_version 13 | defined?(Bundler::VERSION) && Bundler::VERSION 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_api_missing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexApiMissing < CompactIndexAPI 7 | get "/fetch/actual/gem/:id" do 8 | $stderr.puts params[:id] 9 | if params[:id] == "rack-1.0.gemspec.rz" 10 | halt 404 11 | else 12 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 13 | end 14 | end 15 | end 16 | 17 | Artifice.activate_with(CompactIndexApiMissing) 18 | -------------------------------------------------------------------------------- /man/bundle-open.ronn: -------------------------------------------------------------------------------- 1 | bundle-open(1) -- Opens the source directory for a gem in your bundle 2 | ===================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle open` [GEM] 7 | 8 | ## DESCRIPTION 9 | 10 | Opens the source directory of the provided GEM in your editor. 11 | 12 | For this to work the `EDITOR` or `BUNDLER_EDITOR` environment variable has to 13 | be set. 14 | 15 | Example: 16 | 17 | bundle open 'rack' 18 | 19 | Will open the source directory for the 'rack' gem in your bundle. 20 | -------------------------------------------------------------------------------- /spec/other/ssl_cert_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/ssl_certs/certificate_manager" 4 | 5 | RSpec.describe "SSL Certificates", :rubygems_master do 6 | hosts = %w( 7 | rubygems.org 8 | index.rubygems.org 9 | rubygems.global.ssl.fastly.net 10 | staging.rubygems.org 11 | ) 12 | 13 | hosts.each do |host| 14 | it "can securely connect to #{host}", :realworld do 15 | Bundler::SSLCerts::CertificateManager.new.connect_to(host) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/support/less_than_proc.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class LessThanProc < Proc 3 | attr_accessor :present 4 | 5 | def self.with(present) 6 | provided = Gem::Version.new(present.dup) 7 | new do |required| 8 | if required =~ /[=><~]/ 9 | !Gem::Requirement.new(required).satisfied_by?(provided) 10 | else 11 | provided < Gem::Version.new(required) 12 | end 13 | end.tap {|l| l.present = present } 14 | end 15 | 16 | def inspect 17 | "\"=< #{present}\"" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit/parser.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | module BundlerVendoredPostIt::PostIt 4 | class Parser 5 | def initialize(file) 6 | @file = file 7 | end 8 | 9 | BUNDLED_WITH = 10 | /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 11 | 12 | def parse 13 | return unless lockfile = File.file?(@file) && File.read(@file) 14 | if lockfile =~ BUNDLED_WITH 15 | Regexp.last_match(1) 16 | else 17 | '< 1.10' 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/line_editor.rb: -------------------------------------------------------------------------------- 1 | require "bundler/vendor/thor/lib/thor/line_editor/basic" 2 | require "bundler/vendor/thor/lib/thor/line_editor/readline" 3 | 4 | class Bundler::Thor 5 | module LineEditor 6 | def self.readline(prompt, options = {}) 7 | best_available.new(prompt, options).readline 8 | end 9 | 10 | def self.best_available 11 | [ 12 | Bundler::Thor::LineEditor::Readline, 13 | Bundler::Thor::LineEditor::Basic 14 | ].detect(&:available?) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/bundler/templates/Executable.standalone: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application '<%= executable %>' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require "pathname" 10 | path = Pathname.new(__FILE__) 11 | $:.unshift File.expand_path "../<%= standalone_path %>", path.realpath 12 | 13 | require "bundler/setup" 14 | load File.expand_path "../<%= executable_path %>", path.realpath 15 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_wrong_dependencies.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexWrongDependencies < CompactIndexAPI 7 | get "/info/:name" do 8 | etag_response do 9 | gem = gems.find {|g| g.name == params[:name] } 10 | gem.versions.each {|gv| gv.dependencies.clear } if gem 11 | CompactIndex.info(gem ? gem.versions : []) 12 | end 13 | end 14 | end 15 | 16 | Artifice.activate_with(CompactIndexWrongDependencies) 17 | -------------------------------------------------------------------------------- /lib/bundler/gemdeps.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Gemdeps 4 | def initialize(runtime) 5 | @runtime = runtime 6 | end 7 | 8 | def requested_specs 9 | @runtime.requested_specs 10 | end 11 | 12 | def specs 13 | @runtime.specs 14 | end 15 | 16 | def dependencies 17 | @runtime.dependencies 18 | end 19 | 20 | def current_dependencies 21 | @runtime.current_dependencies 22 | end 23 | 24 | def requires 25 | @runtime.requires 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | load File.expand_path("../with_rubygems", __FILE__) if ENV["RGV"] 5 | 6 | require "rubygems" 7 | 8 | bundler_spec = Gem::Specification.load(File.expand_path("../../bundler.gemspec", __FILE__)) 9 | bundler_spec.dependencies.each do |dep| 10 | begin 11 | gem dep.name, dep.requirement 12 | rescue Gem::LoadError => e 13 | $stderr.puts "#{e.message} (#{e.class})" 14 | end 15 | end 16 | 17 | Gem.finish_resolve if Gem.respond_to?(:finish_resolve) 18 | 19 | load Gem.bin_path("rake", "rake") 20 | -------------------------------------------------------------------------------- /man/bundle-clean.ronn: -------------------------------------------------------------------------------- 1 | bundle-clean(1) -- Cleans up unused gems in your bundler directory 2 | ================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle clean` [--dry-run] [--force] 7 | 8 | ## DESCRIPTION 9 | 10 | This command will remove all unused gems in your bundler directory. This is 11 | useful when you have made many changes to your gem dependencies. 12 | 13 | ## OPTIONS 14 | 15 | * `--dry-run`: 16 | Print the changes, but do not clean the unused gems. 17 | * `--force`: 18 | Force a clean even if `--path` is not set. 19 | -------------------------------------------------------------------------------- /man/index.txt: -------------------------------------------------------------------------------- 1 | Gemfile(5) gemfile.5 2 | bundle-install bundle-install.1 3 | bundle-update bundle-update.1 4 | bundle-package bundle-package.1 5 | bundle-exec bundle-exec.1 6 | bundle-config bundle-config.1 7 | bundle-platform bundle-platform.1 8 | bundle-gem bundle-gem.1 9 | bundle-clean bundle-clean.1 10 | bundle-check bundle-check.1 11 | bundle-init bundle-init.1 12 | bundle-inject bundle-inject.1 13 | bundle-open bundle-open.1 14 | bundle-show bundle-show.1 15 | bundle-viz bundle-viz.1 16 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_host_redirect.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexHostRedirect < CompactIndexAPI 7 | get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do 8 | redirect "http://bundler.localgemserver.test#{request.path_info}" 9 | end 10 | 11 | get "/versions" do 12 | status 404 13 | end 14 | 15 | get "/api/v1/dependencies" do 16 | status 404 17 | end 18 | end 19 | 20 | Artifice.activate_with(CompactIndexHostRedirect) 21 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_fallback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointFallback < Endpoint 7 | DEPENDENCY_LIMIT = 60 8 | 9 | get "/api/v1/dependencies" do 10 | if params[:gems] && params[:gems].size <= DEPENDENCY_LIMIT 11 | Marshal.dump(dependencies_for(params[:gems])) 12 | else 13 | halt 413, "Too many gems to resolve, please request less than #{DEPENDENCY_LIMIT} gems" 14 | end 15 | end 16 | end 17 | 18 | Artifice.activate_with(EndpointFallback) 19 | -------------------------------------------------------------------------------- /lib/bundler/templates/Executable: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> 2 | # frozen_string_literal: true 3 | # 4 | # This file was generated by Bundler. 5 | # 6 | # The application '<%= executable %>' is installed as part of a gem, and 7 | # this file is here to facilitate running it. 8 | # 9 | 10 | require "pathname" 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>", 12 | Pathname.new(__FILE__).realpath) 13 | 14 | require "rubygems" 15 | require "bundler/setup" 16 | 17 | load Gem.bin_path("<%= spec.name %>", "<%= executable %>") 18 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_strict_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointStrictBasicAuthentication < Endpoint 7 | before do 8 | unless env["HTTP_AUTHORIZATION"] 9 | halt 401, "Authentication info not supplied" 10 | end 11 | 12 | # Only accepts password == "password" 13 | unless env["HTTP_AUTHORIZATION"] == "Basic dXNlcjpwYXNz" 14 | halt 403, "Authentication failed" 15 | end 16 | end 17 | end 18 | 19 | Artifice.activate_with(EndpointStrictBasicAuthentication) 20 | -------------------------------------------------------------------------------- /man/bundle-init.ronn: -------------------------------------------------------------------------------- 1 | bundle-init(1) -- Generates a Gemfile into the current working directory 2 | ======================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle init` [--gemspec=FILE] 7 | 8 | ## DESCRIPTION 9 | 10 | Init generates a default `Gemfile(5)` in the current working directory. When 11 | adding a `Gemfile(5)` to a gem with a gemspec, the `--gemspec` option will 12 | automatically add each dependency listed in the gemspec file to the newly 13 | created `Gemfile(5)`. 14 | 15 | ## OPTIONS 16 | 17 | * `--gemspec`: 18 | Use the specified .gemspec to create the `Gemfile(5)` 19 | -------------------------------------------------------------------------------- /man/bundle-show.ronn: -------------------------------------------------------------------------------- 1 | bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem 2 | ========================================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle show` [GEM] 7 | [--paths] 8 | 9 | ## DESCRIPTION 10 | 11 | Without the [GEM] option, `show` will print a list of the names and versions of 12 | all gems that are required by your `Gemfile(5)`. 13 | 14 | Calling show with [GEM] will list the exact location of that gem on your 15 | machine. 16 | 17 | ## OPTIONS 18 | 19 | * `--paths`: 20 | List the paths of all gems that are required by your `Gemfile(5)`. 21 | -------------------------------------------------------------------------------- /spec/other/cli_dispatch_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle command names" do 5 | it "work when given fully" do 6 | bundle "install" 7 | expect(err).to lack_errors 8 | expect(out).not_to match(/Ambiguous command/) 9 | end 10 | 11 | it "work when not ambiguous" do 12 | bundle "ins" 13 | expect(err).to lack_errors 14 | expect(out).not_to match(/Ambiguous command/) 15 | end 16 | 17 | it "print a friendly error when ambiguous" do 18 | bundle "in" 19 | expect(err).to lack_errors 20 | expect(out).to match(/Ambiguous command/) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_strict_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexStrictBasicAuthentication < CompactIndexAPI 7 | before do 8 | unless env["HTTP_AUTHORIZATION"] 9 | halt 401, "Authentication info not supplied" 10 | end 11 | 12 | # Only accepts password == "password" 13 | unless env["HTTP_AUTHORIZATION"] == "Basic dXNlcjpwYXNz" 14 | halt 403, "Authentication failed" 15 | end 16 | end 17 | end 18 | 19 | Artifice.activate_with(CompactIndexStrictBasicAuthentication) 20 | -------------------------------------------------------------------------------- /lib/bundler/plugin/installer/rubygems.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Bundler 4 | module Plugin 5 | class Installer 6 | class Rubygems < Bundler::Source::Rubygems 7 | def version_message(spec) 8 | "#{spec.name} #{spec.version}" 9 | end 10 | 11 | private 12 | 13 | def requires_sudo? 14 | false # Will change on implementation of project level plugins 15 | end 16 | 17 | def rubygems_dir 18 | Plugin.root 19 | end 20 | 21 | def cache_path 22 | Plugin.cache 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /man/bundle-inject.ronn: -------------------------------------------------------------------------------- 1 | bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile 2 | ========================================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle inject` [GEM] [VERSION] 7 | 8 | ## DESCRIPTION 9 | 10 | Adds the named gem(s) with their version requirements to the resolved 11 | `Gemfile(5)`. 12 | 13 | This command will add the gem to both your `Gemfile(5)` and Gemfile.lock if it 14 | isn't listed yet. 15 | 16 | Example: 17 | 18 | bundle install 19 | bundle inject 'rack' '> 0' 20 | 21 | This will inject the 'rack' gem with a version greater than 0 in your 22 | `Gemfile(5)` and Gemfile.lock 23 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_wrong_gem_checksum.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexWrongGemChecksum < CompactIndexAPI 7 | get "/info/:name" do 8 | etag_response do 9 | name = params[:name] 10 | gem = gems.find {|g| g.name == name } 11 | checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 } 12 | versions = gem ? gem.versions : [] 13 | versions.each {|v| v.checksum = checksum } 14 | CompactIndex.info(versions) 15 | end 16 | end 17 | end 18 | 19 | Artifice.activate_with(CompactIndexWrongGemChecksum) 20 | -------------------------------------------------------------------------------- /spec/support/code_climate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Spec 3 | module CodeClimate 4 | def self.setup 5 | require "codeclimate-test-reporter" 6 | ::CodeClimate::TestReporter.start 7 | configure_exclusions 8 | rescue LoadError 9 | # it's fine if CodeClimate isn't set up 10 | nil 11 | end 12 | 13 | def self.configure_exclusions 14 | SimpleCov.start do 15 | add_filter "/bin/" 16 | add_filter "/lib/bundler/man/" 17 | add_filter "/lib/bundler/vendor/" 18 | add_filter "/man/" 19 | add_filter "/pkg/" 20 | add_filter "/spec/" 21 | add_filter "/tmp/" 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/bundler/deprecate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | if defined? ::Deprecate 4 | Deprecate = ::Deprecate 5 | elsif defined? Gem::Deprecate 6 | Deprecate = Gem::Deprecate 7 | else 8 | class Deprecate; end 9 | end 10 | 11 | unless Deprecate.respond_to?(:skip_during) 12 | def Deprecate.skip_during 13 | original = skip 14 | self.skip = true 15 | yield 16 | ensure 17 | self.skip = original 18 | end 19 | end 20 | 21 | unless Deprecate.respond_to?(:skip) 22 | def Deprecate.skip 23 | @skip 24 | end 25 | end 26 | 27 | unless Deprecate.respond_to?(:skip=) 28 | def Deprecate.skip=(skip) 29 | @skip = skip 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb: -------------------------------------------------------------------------------- 1 | class Bundler::Thor 2 | module LineEditor 3 | class Basic 4 | attr_reader :prompt, :options 5 | 6 | def self.available? 7 | true 8 | end 9 | 10 | def initialize(prompt, options) 11 | @prompt = prompt 12 | @options = options 13 | end 14 | 15 | def readline 16 | $stdout.print(prompt) 17 | get_input 18 | end 19 | 20 | private 21 | 22 | def get_input 23 | if echo? 24 | $stdin.gets 25 | else 26 | $stdin.noecho(&:gets) 27 | end 28 | end 29 | 30 | def echo? 31 | options.fetch(:echo, true) 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/bundler/cli/clean.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Clean 4 | attr_reader :options 5 | 6 | def initialize(options) 7 | @options = options 8 | end 9 | 10 | def run 11 | require_path_or_force unless options[:"dry-run"] 12 | Bundler.load.clean(options[:"dry-run"]) 13 | end 14 | 15 | protected 16 | 17 | def require_path_or_force 18 | if !Bundler.settings[:path] && !options[:force] 19 | Bundler.ui.error "Cleaning all the gems on your system is dangerous! " \ 20 | "If you're sure you want to remove every system gem not in this " \ 21 | "bundle, run `bundle clean --force`." 22 | exit 1 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/update/path_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "path sources" do 5 | describe "bundle update --source" do 6 | it "shows the previous version of the gem when updated from path source" do 7 | build_lib "activesupport", "2.3.5", :path => lib_path("rails/activesupport") 8 | 9 | install_gemfile <<-G 10 | gem "activesupport", :path => "#{lib_path("rails/activesupport")}" 11 | G 12 | 13 | build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport") 14 | 15 | bundle "update --source activesupport" 16 | expect(out).to include("Using activesupport 3.0 (was 2.3.5) from source at `#{lib_path("rails/activesupport")}`") 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /doc/development/RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | _Release process documentation is in progress, see [PR 5252](https://github.com/bundler/bundler/pull/5252)._ 4 | 5 | ## Beta testing 6 | 7 | Early releases require heavy testing, especially across various system setups. We :heart: testers, and are big fans of anyone who can run `gem install bundler --pre` and try out upcoming releases in their development and staging environments. 8 | 9 | There may not always be prereleases or beta versions of Bundler. The Bundler team will tweet from the [@bundlerio account](http://twitter.com/bundlerio) when a prerelease or beta version becomes available. You are also always welcome to try checking out master and building a gem yourself if you want to try out the latest changes. 10 | -------------------------------------------------------------------------------- /lib/bundler/match_platform.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/gem_helpers" 3 | 4 | module Bundler 5 | module MatchPlatform 6 | include GemHelpers 7 | 8 | def match_platform(p) 9 | MatchPlatform.platforms_match?(platform, p) 10 | end 11 | 12 | def self.platforms_match?(gemspec_platform, local_platform) 13 | return true if gemspec_platform.nil? 14 | return true if Gem::Platform::RUBY == gemspec_platform 15 | return true if local_platform == gemspec_platform 16 | gemspec_platform = Gem::Platform.new(gemspec_platform) 17 | return true if GemHelpers.generic(gemspec_platform) === local_platform 18 | return true if gemspec_platform === local_platform 19 | 20 | false 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/install/gems/win32_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install with win32-generated lockfile" do 5 | it "should read lockfile" do 6 | File.open(bundled_app("Gemfile.lock"), "wb") do |f| 7 | f << "GEM\r\n" 8 | f << " remote: file:#{gem_repo1}/\r\n" 9 | f << " specs:\r\n" 10 | f << "\r\n" 11 | f << " rack (1.0.0)\r\n" 12 | f << "\r\n" 13 | f << "PLATFORMS\r\n" 14 | f << " ruby\r\n" 15 | f << "\r\n" 16 | f << "DEPENDENCIES\r\n" 17 | f << " rack\r\n" 18 | end 19 | 20 | install_gemfile <<-G 21 | source "file://#{gem_repo1}" 22 | 23 | gem "rack" 24 | G 25 | expect(exitstatus).to eq(0) if exitstatus 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /doc/contributing/GETTING_HELP.md: -------------------------------------------------------------------------------- 1 | # Getting help 2 | 3 | If you have any questions after reading the documentation for contributing, please feel free to contact either [@indirect](https://github.com/indirect), [@segiddins](https://github.com/segiddins), or [@RochesterinNYC](https://github.com/RochesterinNYC). They are all happy to provide help working through your first bug fix or thinking through the problem you’re trying to resolve. 4 | 5 | The best ways to get in touch are: 6 | 7 | * [Bundler Slack](https://bundler.slack.com). 8 | * Not a member of the Slack? Join the Bundler team slack [here](http://slack.bundler.io/)! 9 | * [Bundler mailing list](http://groups.google.com/group/ruby-bundler) 10 | 11 | You may also find our guide on [filing issues](ISSUES.md) to be helpful as well! 12 | -------------------------------------------------------------------------------- /doc/development/NEW_FEATURES.md: -------------------------------------------------------------------------------- 1 | # Adding New Features 2 | 3 | If you would like to add a new feature to Bundler, please follow these steps: 4 | 5 | 1. [Create an issue](https://github.com/bundler/bundler/issues/new) with the [`feature-request` label](https://github.com/bundler/bundler/labels/type:%20feature-request) to discuss your feature. 6 | 2. Base your commits on the master branch, since we follow [SemVer](http://semver.org) and don't add new features to old releases. 7 | 3. Commit the code and at least one test covering your changes to a feature branch in your fork. 8 | 4. Send us a [pull request](PULL_REQUESTS.md) from your feature branch. 9 | 10 | If you don't hear back immediately, don’t get discouraged! We all have day jobs, but we respond to most tickets within a day or two. 11 | -------------------------------------------------------------------------------- /lib/bundler/capistrano.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Capistrano task for Bundler. 3 | # 4 | # Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and 5 | # Bundler will be activated after each new deployment. 6 | require "bundler/deployment" 7 | require "capistrano/version" 8 | 9 | if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") 10 | raise "For Capistrano 3.x integration, please use http://github.com/capistrano/bundler" 11 | end 12 | 13 | Capistrano::Configuration.instance(:must_exist).load do 14 | before "deploy:finalize_update", "bundle:install" 15 | Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) 16 | set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } 17 | end 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Bundler 2 | 3 | Welcome to Bundler! We are so happy that you're here. We know it can be daunting to joining a new open source project, so here's a quick overview of what you can expect from this documentation. 4 | 5 | Bundler welcomes contributions from *everyone*. While contributing, please follow the project [code of conduct](http://bundler.io/conduct.html), so that everyone can be included. 6 | 7 | ## Quick start 8 | 9 | Some guides you might find useful: 10 | 11 | * [Submitting pull requests](doc/development/PULL_REQUESTS.md) 12 | * [Filing an issue](doc/contributing/ISSUES.md) 13 | * [Bug triage](doc/contributing/BUG_TRIAGE.md) 14 | 15 | ## Comprehensive guides 16 | 17 | Not finding what you're looking for? More comprehensive guides are [available here](doc/README.md). 18 | -------------------------------------------------------------------------------- /doc/development/README.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | So, you're ready to start contributing to Bundler! You've come to the right place. Here you'll find an overview of how to work on Bundler locally and a description of the process from code to release. 4 | 5 | ##[Development setup](SETUP.md) 6 | 7 | Guidelines for setting up your local development environment. 8 | 9 | ##[Submitting pull requests](PULL_REQUESTS.md) 10 | 11 | An overview of our preferred PR process, including how to run the test suite and what to expect when you submit code for review. 12 | 13 | ##[Adding new features](NEW_FEATURES.md) 14 | 15 | Guidelines for proposing and writing new features for Bundler. 16 | 17 | ##[Releasing Bundler](RELEASING.md) 18 | 19 | A broad-strokes overview of the release process adhered to by the Bundler core team. 20 | -------------------------------------------------------------------------------- /lib/bundler/psyched_yaml.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Psych could be a gem, so try to ask for it 3 | begin 4 | gem "psych" 5 | rescue LoadError 6 | end if defined?(gem) 7 | 8 | # Psych could be in the stdlib 9 | # but it's too late if Syck is already loaded 10 | begin 11 | require "psych" unless defined?(Syck) 12 | rescue LoadError 13 | # Apparently Psych wasn't available. Oh well. 14 | end 15 | 16 | # At least load the YAML stdlib, whatever that may be 17 | require "yaml" unless defined?(YAML.dump) 18 | 19 | module Bundler 20 | # On encountering invalid YAML, 21 | # Psych raises Psych::SyntaxError 22 | if defined?(::Psych::SyntaxError) 23 | YamlLibrarySyntaxError = ::Psych::SyntaxError 24 | else # Syck raises ArgumentError 25 | YamlLibrarySyntaxError = ::ArgumentError 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/Rakefile.tt: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | <% if config[:test] == "minitest" -%> 3 | require "rake/testtask" 4 | 5 | Rake::TestTask.new(:test) do |t| 6 | t.libs << "test" 7 | t.libs << "lib" 8 | t.test_files = FileList["test/**/*_test.rb"] 9 | end 10 | 11 | <% elsif config[:test] == "rspec" -%> 12 | require "rspec/core/rake_task" 13 | 14 | RSpec::Core::RakeTask.new(:spec) 15 | 16 | <% end -%> 17 | <% if config[:ext] -%> 18 | require "rake/extensiontask" 19 | 20 | task :build => :compile 21 | 22 | Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext| 23 | ext.lib_dir = "lib/<%= config[:namespaced_path] %>" 24 | end 25 | 26 | task :default => [:clobber, :compile, :<%= config[:test_task] %>] 27 | <% else -%> 28 | task :default => :<%= config[:test_task] %> 29 | <% end -%> 30 | -------------------------------------------------------------------------------- /lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb: -------------------------------------------------------------------------------- 1 | require 'net/protocol' 2 | 3 | ## 4 | # Aaron Patterson's monkeypatch (accepted into 1.9.1) to fix Net::HTTP's speed 5 | # problems. 6 | # 7 | # http://gist.github.com/251244 8 | 9 | class Net::BufferedIO #:nodoc: 10 | alias :old_rbuf_fill :rbuf_fill 11 | 12 | def rbuf_fill 13 | if @io.respond_to? :read_nonblock then 14 | begin 15 | @rbuf << @io.read_nonblock(65536) 16 | rescue Errno::EWOULDBLOCK, Errno::EAGAIN => e 17 | retry if IO.select [@io], nil, nil, @read_timeout 18 | raise Timeout::Error, e.message 19 | end 20 | else # SSL sockets do not have read_nonblock 21 | timeout @read_timeout do 22 | @rbuf << @io.sysread(65536) 23 | end 24 | end 25 | end 26 | end if RUBY_VERSION < '1.9' 27 | 28 | -------------------------------------------------------------------------------- /spec/plugins/hook_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "hook plugins" do 5 | before do 6 | build_repo2 do 7 | build_plugin "before-install-plugin" do |s| 8 | s.write "plugins.rb", <<-RUBY 9 | Bundler::Plugin::API.hook "before-install-all" do |deps| 10 | puts "gems to be installed \#{deps.map(&:name).join(", ")}" 11 | end 12 | RUBY 13 | end 14 | end 15 | 16 | bundle "plugin install before-install-plugin --source file://#{gem_repo2}" 17 | end 18 | 19 | it "runs after a rubygem is installed" do 20 | install_gemfile <<-G 21 | source "file://#{gem_repo1}" 22 | gem "rake" 23 | gem "rack" 24 | G 25 | 26 | expect(out).to include "gems to be installed rake, rack" 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/bundler/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Ruby 1.9.3 and old RubyGems don't play nice with frozen version strings 4 | # rubocop:disable MutableConstant 5 | 6 | module Bundler 7 | # We're doing this because we might write tests that deal 8 | # with other versions of bundler and we are unsure how to 9 | # handle this better. 10 | VERSION = "1.15.0.pre.1" unless defined?(::Bundler::VERSION) 11 | 12 | def self.overwrite_loaded_gem_version 13 | begin 14 | require "rubygems" 15 | rescue LoadError 16 | return 17 | end 18 | return unless bundler_spec = Gem.loaded_specs["bundler"] 19 | return if bundler_spec.version == VERSION 20 | bundler_spec.version = Bundler::VERSION 21 | end 22 | private_class_method :overwrite_loaded_gem_version 23 | overwrite_loaded_gem_version 24 | end 25 | -------------------------------------------------------------------------------- /lib/bundler/ruby_dsl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | module RubyDsl 4 | def ruby(*ruby_version) 5 | options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {} 6 | ruby_version.flatten! 7 | raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil? 8 | raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? 9 | 10 | if options[:engine] == "ruby" && options[:engine_version] && 11 | ruby_version != Array(options[:engine_version]) 12 | raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" 13 | end 14 | @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/bundler/worker_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/worker" 4 | 5 | RSpec.describe Bundler::Worker do 6 | let(:size) { 5 } 7 | let(:name) { "Spec Worker" } 8 | let(:function) { proc {|object, worker_number| [object, worker_number] } } 9 | subject { described_class.new(size, name, function) } 10 | 11 | after { subject.stop } 12 | 13 | describe "#initialize" do 14 | context "when Thread.start raises ThreadError" do 15 | it "raises when no threads can be created" do 16 | allow(Thread).to receive(:start).and_raise(ThreadError, "error creating thread") 17 | 18 | expect { subject.enq "a" }.to raise_error(Bundler::ThreadCreationError, "Failed to create threads for the Spec Worker worker: error creating thread") 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/commands/licenses_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle licenses" do 5 | before :each do 6 | install_gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | gem "rails" 9 | gem "with_license" 10 | G 11 | end 12 | 13 | it "prints license information for all gems in the bundle" do 14 | bundle "licenses" 15 | 16 | expect(out).to include("bundler: Unknown") 17 | expect(out).to include("with_license: MIT") 18 | end 19 | 20 | it "performs an automatic bundle install" do 21 | gemfile <<-G 22 | source "file://#{gem_repo1}" 23 | gem "rails" 24 | gem "with_license" 25 | gem "foo" 26 | G 27 | 28 | bundle "config auto_install 1" 29 | bundle :licenses 30 | expect(out).to include("Installing foo 1.0") 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_extra.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointExtra < Endpoint 7 | get "/extra/api/v1/dependencies" do 8 | halt 404 9 | end 10 | 11 | get "/extra/specs.4.8.gz" do 12 | File.read("#{gem_repo2}/specs.4.8.gz") 13 | end 14 | 15 | get "/extra/prerelease_specs.4.8.gz" do 16 | File.read("#{gem_repo2}/prerelease_specs.4.8.gz") 17 | end 18 | 19 | get "/extra/quick/Marshal.4.8/:id" do 20 | redirect "/extra/fetch/actual/gem/#{params[:id]}" 21 | end 22 | 23 | get "/extra/fetch/actual/gem/:id" do 24 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 25 | end 26 | 27 | get "/extra/gems/:id" do 28 | File.read("#{gem_repo2}/gems/#{params[:id]}") 29 | end 30 | end 31 | 32 | Artifice.activate_with(EndpointExtra) 33 | -------------------------------------------------------------------------------- /spec/lock/git_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle lock with git gems" do 5 | before :each do 6 | build_git "foo" 7 | 8 | install_gemfile <<-G 9 | gem 'foo', :git => "#{lib_path("foo-1.0")}" 10 | G 11 | end 12 | 13 | it "doesn't break right after running lock" do 14 | expect(the_bundle).to include_gems "foo 1.0.0" 15 | end 16 | 17 | it "locks a git source to the current ref" do 18 | update_git "foo" 19 | bundle :install 20 | 21 | run <<-RUBY 22 | require 'foo' 23 | puts "WIN" unless defined?(FOO_PREV_REF) 24 | RUBY 25 | 26 | expect(out).to eq("WIN") 27 | end 28 | 29 | it "provides correct #full_gem_path" do 30 | run <<-RUBY 31 | puts Bundler.rubygems.find_name('foo').first.full_gem_path 32 | RUBY 33 | expect(out).to eq(bundle("show foo")) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/support/the_bundle.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "support/helpers" 3 | require "support/path" 4 | 5 | module Spec 6 | class TheBundle 7 | include Spec::Helpers 8 | include Spec::Path 9 | 10 | attr_accessor :bundle_dir 11 | 12 | def initialize(opts = {}) 13 | opts = opts.dup 14 | @bundle_dir = Pathname.new(opts.delete(:bundle_dir) { bundled_app }) 15 | raise "Too many options! #{opts}" unless opts.empty? 16 | end 17 | 18 | def to_s 19 | "the bundle" 20 | end 21 | alias_method :inspect, :to_s 22 | 23 | def locked? 24 | lockfile.file? 25 | end 26 | 27 | def lockfile 28 | bundle_dir.join("Gemfile.lock") 29 | end 30 | 31 | def locked_gems 32 | raise "Cannot read lockfile if it doesn't exist" unless locked? 33 | Bundler::LockfileParser.new(lockfile.read) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/bundler/cli/open.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | require "shellwords" 4 | 5 | module Bundler 6 | class CLI::Open 7 | attr_reader :options, :name 8 | def initialize(options, name) 9 | @options = options 10 | @name = name 11 | end 12 | 13 | def run 14 | editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } 15 | return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor 16 | return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) 17 | path = spec.full_gem_path 18 | Dir.chdir(path) do 19 | command = Shellwords.split(editor) + [path] 20 | Bundler.with_clean_env do 21 | system(*command) 22 | end || Bundler.ui.info("Could not run '#{command.join(" ")}'") 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' 3 | module Bundler::Molinillo 4 | class DependencyGraph 5 | # @!visibility private 6 | # @see DependencyGraph#tag 7 | class Tag < Action 8 | # @!group Action 9 | 10 | # (see Action.action_name) 11 | def self.action_name 12 | :tag 13 | end 14 | 15 | # (see Action#up) 16 | def up(_graph) 17 | end 18 | 19 | # (see Action#down) 20 | def down(_graph) 21 | end 22 | 23 | # @!group Tag 24 | 25 | # @return [Object] An opaque tag 26 | attr_reader :tag 27 | 28 | # Initialize an action to tag a state of a dependency graph 29 | # @param [Object] tag an opaque tag 30 | def initialize(tag) 31 | @tag = tag 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit/installer.rb: -------------------------------------------------------------------------------- 1 | module BundlerVendoredPostIt::PostIt 2 | class Installer 3 | def initialize(bundler_version) 4 | @bundler_version = bundler_version 5 | end 6 | 7 | def installed? 8 | if Gem::Specification.respond_to?(:find_by_name) 9 | !Gem::Specification.find_by_name('bundler', @bundler_version).nil? 10 | else 11 | requirement = Gem::Requirement.new(@bundler_version) 12 | Gem.source_index.gems.values.any? do |s| 13 | s.name == 'bundler' && requirement.satisfied_by?(s.version) 14 | end 15 | end 16 | rescue LoadError 17 | false 18 | end 19 | 20 | def install! 21 | return if installed? 22 | require 'rubygems/dependency_installer' 23 | installer = Gem::DependencyInstaller.new 24 | installer.install('bundler', @bundler_version) 25 | installer.installed_gems 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /man/bundle-check.ronn: -------------------------------------------------------------------------------- 1 | bundle-check(1) -- Verifies if dependencies are satisfied by installed gems 2 | =========================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle check` [--dry-run] 7 | [--gemfile=FILE] 8 | [--path=PATH] 9 | 10 | ## DESCRIPTION 11 | 12 | `check` searches the local machine for each of the gems requested in the 13 | Gemfile. If all gems are found, Bundler prints a success message and exits with 14 | a status of 0. 15 | 16 | If not, the first missing gem is listed and Bundler exits status 1. 17 | 18 | ## OPTIONS 19 | 20 | * `--dry-run`: 21 | Locks the `Gemfile(5)` before running the command. 22 | * `--gemfile`: 23 | Use the specified gemfile instead of the `Gemfile(5)` 24 | * `--path`: 25 | Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). 26 | Bundler will remember this value for future installs on this machine. 27 | -------------------------------------------------------------------------------- /spec/bundler/plugin/source_list_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::Plugin::SourceList do 5 | SourceList = Bundler::Plugin::SourceList 6 | 7 | before do 8 | allow(Bundler).to receive(:root) { Pathname.new "/" } 9 | end 10 | 11 | subject(:source_list) { SourceList.new } 12 | 13 | describe "adding sources uses classes for plugin" do 14 | it "uses Plugin::Installer::Rubygems for rubygems sources" do 15 | source = source_list. 16 | add_rubygems_source("remotes" => ["https://existing-rubygems.org"]) 17 | expect(source).to be_instance_of(Bundler::Plugin::Installer::Rubygems) 18 | end 19 | 20 | it "uses Plugin::Installer::Git for git sources" do 21 | source = source_list. 22 | add_git_source("uri" => "git://existing-git.org/path.git") 23 | expect(source).to be_instance_of(Bundler::Plugin::Installer::Git) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_extra_api.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointExtraApi < Endpoint 7 | get "/extra/api/v1/dependencies" do 8 | deps = dependencies_for(params[:gems], gem_repo4) 9 | Marshal.dump(deps) 10 | end 11 | 12 | get "/extra/specs.4.8.gz" do 13 | File.read("#{gem_repo4}/specs.4.8.gz") 14 | end 15 | 16 | get "/extra/prerelease_specs.4.8.gz" do 17 | File.read("#{gem_repo4}/prerelease_specs.4.8.gz") 18 | end 19 | 20 | get "/extra/quick/Marshal.4.8/:id" do 21 | redirect "/extra/fetch/actual/gem/#{params[:id]}" 22 | end 23 | 24 | get "/extra/fetch/actual/gem/:id" do 25 | File.read("#{gem_repo4}/quick/Marshal.4.8/#{params[:id]}") 26 | end 27 | 28 | get "/extra/gems/:id" do 29 | File.read("#{gem_repo4}/gems/#{params[:id]}") 30 | end 31 | end 32 | 33 | Artifice.activate_with(EndpointExtraApi) 34 | -------------------------------------------------------------------------------- /lib/bundler/plugin/source_list.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Bundler 4 | # SourceList object to be used while parsing the Gemfile, setting the 5 | # approptiate options to be used with Source classes for plugin installation 6 | module Plugin 7 | class SourceList < Bundler::SourceList 8 | def initialize 9 | @path_sources = [] 10 | @git_sources = [] 11 | @rubygems_aggregate = Plugin::Installer::Rubygems.new 12 | @rubygems_sources = [] 13 | end 14 | 15 | def add_git_source(options = {}) 16 | add_source_to_list Plugin::Installer::Git.new(options), git_sources 17 | end 18 | 19 | def add_rubygems_source(options = {}) 20 | add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources 21 | end 22 | 23 | def all_sources 24 | path_sources + git_sources + rubygems_sources 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_extra.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexExtra < CompactIndexAPI 7 | get "/extra/versions" do 8 | halt 404 9 | end 10 | 11 | get "/extra/api/v1/dependencies" do 12 | halt 404 13 | end 14 | 15 | get "/extra/specs.4.8.gz" do 16 | File.read("#{gem_repo2}/specs.4.8.gz") 17 | end 18 | 19 | get "/extra/prerelease_specs.4.8.gz" do 20 | File.read("#{gem_repo2}/prerelease_specs.4.8.gz") 21 | end 22 | 23 | get "/extra/quick/Marshal.4.8/:id" do 24 | redirect "/extra/fetch/actual/gem/#{params[:id]}" 25 | end 26 | 27 | get "/extra/fetch/actual/gem/:id" do 28 | File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") 29 | end 30 | 31 | get "/extra/gems/:id" do 32 | File.read("#{gem_repo2}/gems/#{params[:id]}") 33 | end 34 | end 35 | 36 | Artifice.activate_with(CompactIndexExtra) 37 | -------------------------------------------------------------------------------- /lib/bundler/dep_proxy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class DepProxy 4 | attr_reader :__platform, :dep 5 | 6 | def initialize(dep, platform) 7 | @dep = dep 8 | @__platform = platform 9 | end 10 | 11 | def hash 12 | @hash ||= dep.hash 13 | end 14 | 15 | def ==(other) 16 | dep == other.dep && __platform == other.__platform 17 | end 18 | 19 | alias_method :eql?, :== 20 | 21 | def type 22 | @dep.type 23 | end 24 | 25 | def name 26 | @dep.name 27 | end 28 | 29 | def requirement 30 | @dep.requirement 31 | end 32 | 33 | def to_s 34 | s = name.dup 35 | s << " (#{requirement})" unless requirement == Gem::Requirement.default 36 | s << " #{__platform}" unless __platform == Gem::Platform::RUBY 37 | s 38 | end 39 | 40 | private 41 | 42 | def method_missing(*args, &blk) 43 | @dep.send(*args, &blk) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /man/bundle-binstubs.ronn: -------------------------------------------------------------------------------- 1 | bundle-binstubs(1) -- Install the binstubs of the listed gems 2 | ============================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle binstubs` [--force] [--path PATH] [--standalone] 7 | 8 | ## DESCRIPTION 9 | 10 | This command generates binstubs for executables in `GEM_NAME`. 11 | Binstubs are put into `bin`, or the `--path` directory if one has been set. 12 | Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. 13 | 14 | ## OPTIONS 15 | 16 | * `--force`: 17 | Overwrite existing binstubs if they exist. 18 | 19 | * `--path`: 20 | The location to install the specified binstubs to. This defaults to `bin`. 21 | 22 | * `--standalone`: 23 | Makes binstubs that can work without depending on Rubygems or Bundler at 24 | runtime. 25 | 26 | ## BUNDLE INSTALL --BINSTUBS 27 | 28 | To create binstubs for all the gems in the bundle you can use the `--binstubs` 29 | flag in [bundle install(1)][bundle-install]. 30 | -------------------------------------------------------------------------------- /lib/bundler/setup.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/postit_trampoline" 3 | require "bundler/shared_helpers" 4 | 5 | if Bundler::SharedHelpers.in_bundle? 6 | require "bundler" 7 | 8 | if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] 9 | begin 10 | Bundler.setup 11 | rescue Bundler::BundlerError => e 12 | puts "\e[31m#{e.message}\e[0m" 13 | puts e.backtrace.join("\n") if ENV["DEBUG"] 14 | if e.is_a?(Bundler::GemNotFound) 15 | puts "\e[33mRun `bundle install` to install missing gems.\e[0m" 16 | end 17 | exit e.status_code 18 | end 19 | else 20 | Bundler.setup 21 | end 22 | 23 | unless ENV["BUNDLE_POSTIT_TRAMPOLINING_VERSION"] 24 | # Add bundler to the load path after disabling system gems 25 | # This is guaranteed to be done already if we've trampolined 26 | bundler_lib = File.expand_path("../..", __FILE__) 27 | $LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib) 28 | end 29 | 30 | Bundler.ui = nil 31 | end 32 | -------------------------------------------------------------------------------- /lib/bundler/cli/add.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | 4 | module Bundler 5 | class CLI::Add 6 | def initialize(options, gem_name) 7 | @gem_name = gem_name 8 | @options = options 9 | @options[:group] = @options[:group].split(",").map(&:strip) if !@options[:group].nil? && !@options[:group].empty? 10 | end 11 | 12 | def run 13 | version = @options[:version].nil? ? nil : @options[:version].split(",").map(&:strip) 14 | 15 | unless version.nil? 16 | version.each do |v| 17 | raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s 18 | end 19 | end 20 | dependency = Bundler::Dependency.new(@gem_name, version, @options) 21 | 22 | Injector.inject([dependency], :conservative_versioning => @options[:version].nil?) # Perform conservative versioning only when version is not specified 23 | Installer.install(Bundler.root, Bundler.definition) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /man/bundle-viz.ronn: -------------------------------------------------------------------------------- 1 | bundle-viz(1) -- Generates a visual dependency graph for your Gemfile 2 | ===================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle viz` [--file=FILE] 7 | [--format=FORMAT] 8 | [--requirements] 9 | [--version] 10 | [--without=GROUP GROUP] 11 | 12 | ## DESCRIPTION 13 | 14 | `viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph. 15 | `viz` requires the ruby-graphviz gem (and its dependencies). 16 | 17 | The associated gems must also be installed via `bundle install(1)`. 18 | 19 | ## OPTIONS 20 | 21 | * `--file`: 22 | The name to use for the generated file. See `--format` option 23 | * `--format`: 24 | This is output format option. Supported format is png, jpg, svg, dot ... 25 | * `--requirements`: 26 | Set to show the version of each required dependency. 27 | * `--version`: 28 | Set to show each gem version. 29 | * `--without`: 30 | Exclude gems that are part of the specified named group. 31 | -------------------------------------------------------------------------------- /spec/cache/cache_path_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle package" do 5 | before do 6 | gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | gem "rack" 9 | G 10 | end 11 | 12 | context "with --cache-path" do 13 | it "caches gems at given path" do 14 | bundle :package, "cache-path" => "vendor/cache-foo" 15 | expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist 16 | end 17 | end 18 | 19 | context "with config cache_path" do 20 | it "caches gems at given path" do 21 | bundle "config cache_path vendor/cache-foo" 22 | bundle :package 23 | expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist 24 | end 25 | end 26 | 27 | context "when given an absolute path" do 28 | it "exits with non-zero status" do 29 | bundle :package, "cache-path" => "/tmp/cache-foo" 30 | expect(out).to match(/must be relative/) 31 | expect(exitstatus).to eq(15) if exitstatus 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/bundler/source/rubygems_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::Source::Rubygems do 5 | before do 6 | allow(Bundler).to receive(:root) { Pathname.new("root") } 7 | end 8 | 9 | describe "caches" do 10 | it "includes Bundler.app_cache" do 11 | expect(subject.caches).to include(Bundler.app_cache) 12 | end 13 | 14 | it "includes GEM_PATH entries" do 15 | Gem.path.each do |path| 16 | expect(subject.caches).to include(File.expand_path("#{path}/cache")) 17 | end 18 | end 19 | 20 | it "is an array of strings or pathnames" do 21 | subject.caches.each do |cache| 22 | expect([String, Pathname]).to include(cache.class) 23 | end 24 | end 25 | end 26 | 27 | describe "#add_remote" do 28 | context "when the source is an HTTP(s) URI with no host" do 29 | it "raises error" do 30 | expect { subject.add_remote("https:rubygems.org") }.to raise_error(ArgumentError) 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/bundler/plugin/installer/git.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Bundler 4 | module Plugin 5 | class Installer 6 | class Git < Bundler::Source::Git 7 | def cache_path 8 | @cache_path ||= begin 9 | git_scope = "#{base_name}-#{uri_hash}" 10 | 11 | Plugin.cache.join("bundler", "git", git_scope) 12 | end 13 | end 14 | 15 | def install_path 16 | @install_path ||= begin 17 | git_scope = "#{base_name}-#{shortref_for_path(revision)}" 18 | 19 | Plugin.root.join("bundler", "gems", git_scope) 20 | end 21 | end 22 | 23 | def version_message(spec) 24 | "#{spec.name} #{spec.version}" 25 | end 26 | 27 | def root 28 | Plugin.root 29 | end 30 | 31 | def generate_bin(spec, disable_extensions = false) 32 | # Need to find a way without code duplication 33 | # For now, we can ignore this 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/bundler/environment_preserver.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class EnvironmentPreserver 4 | # @param env [ENV] 5 | # @param keys [Array] 6 | def initialize(env, keys) 7 | @original = env.to_hash 8 | @keys = keys 9 | @prefix = "BUNDLER_ORIG_" 10 | end 11 | 12 | # @return [Hash] 13 | def backup 14 | env = @original.clone 15 | @keys.each do |key| 16 | value = env[key] 17 | original_value = env[@prefix + key] 18 | if !value.nil? && !value.empty? && original_value.nil? 19 | env[@prefix + key] = value 20 | end 21 | end 22 | env 23 | end 24 | 25 | # @return [Hash] 26 | def restore 27 | env = @original.clone 28 | @keys.each do |key| 29 | value_original = env[@prefix + key] 30 | unless value_original.nil? || value_original.empty? 31 | env[key] = value_original 32 | env.delete(@prefix + key) 33 | end 34 | end 35 | env 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/bundler/cli/viz.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Viz 4 | attr_reader :options, :gem_name 5 | def initialize(options) 6 | @options = options 7 | end 8 | 9 | def run 10 | require "graphviz" 11 | 12 | options[:without] = options[:without].join(":").tr(" ", ":").split(":") 13 | output_file = File.expand_path(options[:file]) 14 | 15 | graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) 16 | graph.viz 17 | rescue LoadError => e 18 | Bundler.ui.error e.inspect 19 | Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" 20 | Bundler.ui.warn "`gem install ruby-graphviz`" 21 | rescue StandardError => e 22 | raise unless e.message =~ /GraphViz not installed or dot not in PATH/ 23 | Bundler.ui.error e.message 24 | Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/bundler/spec_set_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::SpecSet do 5 | let(:specs) do 6 | [ 7 | build_spec("a", "1.0"), 8 | build_spec("b", "1.0"), 9 | build_spec("c", "1.1") do |s| 10 | s.dep "a", "< 2.0" 11 | s.dep "e", "> 0" 12 | end, 13 | build_spec("d", "2.0") do |s| 14 | s.dep "a", "1.0" 15 | s.dep "c", "~> 1.0" 16 | end, 17 | build_spec("e", "1.0.0.pre.1"), 18 | ].flatten 19 | end 20 | subject { described_class.new(specs) } 21 | 22 | context "enumerable methods" do 23 | it "has a length" do 24 | expect(subject.length).to eq(5) 25 | end 26 | 27 | it "has a size" do 28 | expect(subject.size).to eq(5) 29 | end 30 | end 31 | 32 | describe "#to_a" do 33 | it "returns the specs in order" do 34 | expect(subject.to_a.map(&:full_name)).to eq %w( 35 | a-1.0 36 | b-1.0 37 | e-1.0.0.pre.1 38 | c-1.1 39 | d-2.0 40 | ) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/error.rb: -------------------------------------------------------------------------------- 1 | class Bundler::Thor 2 | # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those 3 | # errors have their backtrace suppressed and are nicely shown to the user. 4 | # 5 | # Errors that are caused by the developer, like declaring a method which 6 | # overwrites a thor keyword, SHOULD NOT raise a Bundler::Thor::Error. This way, we 7 | # ensure that developer errors are shown with full backtrace. 8 | class Error < StandardError 9 | end 10 | 11 | # Raised when a command was not found. 12 | class UndefinedCommandError < Error 13 | end 14 | UndefinedTaskError = UndefinedCommandError 15 | 16 | class AmbiguousCommandError < Error 17 | end 18 | AmbiguousTaskError = AmbiguousCommandError 19 | 20 | # Raised when a command was found, but not invoked properly. 21 | class InvocationError < Error 22 | end 23 | 24 | class UnknownArgumentError < Error 25 | end 26 | 27 | class RequiredArgumentMissingError < InvocationError 28 | end 29 | 30 | class MalformattedArgumentError < InvocationError 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/install/failure_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install" do 5 | context "installing a gem fails" do 6 | it "prints out why that gem was being installed" do 7 | build_repo2 do 8 | build_gem "activesupport", "2.3.2" do |s| 9 | s.extensions << "Rakefile" 10 | s.write "Rakefile", <<-RUBY 11 | task :default do 12 | abort "make installing activesupport-2.3.2 fail" 13 | end 14 | RUBY 15 | end 16 | end 17 | 18 | install_gemfile <<-G 19 | source "file:#{gem_repo2}" 20 | gem "rails" 21 | G 22 | expect(out).to end_with(<<-M.strip) 23 | An error occurred while installing activesupport (2.3.2), and Bundler cannot continue. 24 | Make sure that `gem install activesupport -v '2.3.2'` succeeds before bundling. 25 | 26 | In Gemfile: 27 | rails was resolved to 2.3.2, which depends on 28 | actionmailer was resolved to 2.3.2, which depends on 29 | activesupport 30 | M 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/support/artifice/endpoint_creds_diff_host.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../endpoint", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class EndpointCredsDiffHost < Endpoint 7 | helpers do 8 | def auth 9 | @auth ||= Rack::Auth::Basic::Request.new(request.env) 10 | end 11 | 12 | def authorized? 13 | auth.provided? && auth.basic? && auth.credentials && auth.credentials == %w(user pass) 14 | end 15 | 16 | def protected! 17 | return if authorized? 18 | response["WWW-Authenticate"] = %(Basic realm="Testing HTTP Auth") 19 | throw(:halt, [401, "Not authorized\n"]) 20 | end 21 | end 22 | 23 | before do 24 | protected! unless request.path_info.include?("/no/creds/") 25 | end 26 | 27 | get "/gems/:id" do 28 | redirect "http://diffhost.com/no/creds/#{params[:id]}" 29 | end 30 | 31 | get "/no/creds/:id" do 32 | if request.host.include?("diffhost") && !auth.provided? 33 | File.read("#{gem_repo1}/gems/#{params[:id]}") 34 | end 35 | end 36 | end 37 | 38 | Artifice.activate_with(EndpointCredsDiffHost) 39 | -------------------------------------------------------------------------------- /lib/bundler/cli/init.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Init 4 | attr_reader :options 5 | def initialize(options) 6 | @options = options 7 | end 8 | 9 | def run 10 | if File.exist?("Gemfile") 11 | Bundler.ui.error "Gemfile already exists at #{SharedHelpers.pwd}/Gemfile" 12 | exit 1 13 | end 14 | 15 | if options[:gemspec] 16 | gemspec = File.expand_path(options[:gemspec]) 17 | unless File.exist?(gemspec) 18 | Bundler.ui.error "Gem specification #{gemspec} doesn't exist" 19 | exit 1 20 | end 21 | spec = Gem::Specification.load(gemspec) 22 | puts "Writing new Gemfile to #{SharedHelpers.pwd}/Gemfile" 23 | File.open("Gemfile", "wb") do |file| 24 | file << "# Generated from #{gemspec}\n" 25 | file << spec.to_gemfile 26 | end 27 | else 28 | puts "Writing new Gemfile to #{SharedHelpers.pwd}/Gemfile" 29 | FileUtils.cp(File.expand_path("../../templates/Gemfile", __FILE__), "Gemfile") 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler::Molinillo 3 | class DependencyGraph 4 | # An action that modifies a {DependencyGraph} that is reversible. 5 | # @abstract 6 | class Action 7 | # rubocop:disable Lint/UnusedMethodArgument 8 | 9 | # @return [Symbol] The name of the action. 10 | def self.action_name 11 | raise 'Abstract' 12 | end 13 | 14 | # Performs the action on the given graph. 15 | # @param [DependencyGraph] graph the graph to perform the action on. 16 | # @return [Void] 17 | def up(graph) 18 | raise 'Abstract' 19 | end 20 | 21 | # Reverses the action on the given graph. 22 | # @param [DependencyGraph] graph the graph to reverse the action on. 23 | # @return [Void] 24 | def down(graph) 25 | raise 'Abstract' 26 | end 27 | 28 | # @return [Action,Nil] The previous action 29 | attr_accessor :previous 30 | 31 | # @return [Action,Nil] The next action 32 | attr_accessor :next 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_creds_diff_host.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexCredsDiffHost < CompactIndexAPI 7 | helpers do 8 | def auth 9 | @auth ||= Rack::Auth::Basic::Request.new(request.env) 10 | end 11 | 12 | def authorized? 13 | auth.provided? && auth.basic? && auth.credentials && auth.credentials == %w(user pass) 14 | end 15 | 16 | def protected! 17 | return if authorized? 18 | response["WWW-Authenticate"] = %(Basic realm="Testing HTTP Auth") 19 | throw(:halt, [401, "Not authorized\n"]) 20 | end 21 | end 22 | 23 | before do 24 | protected! unless request.path_info.include?("/no/creds/") 25 | end 26 | 27 | get "/gems/:id" do 28 | redirect "http://diffhost.com/no/creds/#{params[:id]}" 29 | end 30 | 31 | get "/no/creds/:id" do 32 | if request.host.include?("diffhost") && !auth.provided? 33 | File.read("#{gem_repo1}/gems/#{params[:id]}") 34 | end 35 | end 36 | end 37 | 38 | Artifice.activate_with(CompactIndexCredsDiffHost) 39 | -------------------------------------------------------------------------------- /spec/support/artifice/fail.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "net/http" 4 | begin 5 | require "net/https" 6 | rescue LoadError 7 | nil # net/https or openssl 8 | end 9 | 10 | # We can't use artifice here because it uses rack 11 | 12 | module Artifice; end # for < 2.0, Net::HTTP::Persistent::SSLReuse 13 | 14 | class Fail < Net::HTTP 15 | # Net::HTTP uses a @newimpl instance variable to decide whether 16 | # to use a legacy implementation. Since we are subclassing 17 | # Net::HTTP, we must set it 18 | @newimpl = true 19 | 20 | def request(req, body = nil, &block) 21 | raise(exception(req)) 22 | end 23 | 24 | # Ensure we don't start a connect here 25 | def connect 26 | end 27 | 28 | def exception(req) 29 | name = ENV.fetch("BUNDLER_SPEC_EXCEPTION") { "Errno::ENETUNREACH" } 30 | const = name.split("::").reduce(Object) {|mod, sym| mod.const_get(sym) } 31 | const.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}") 32 | end 33 | end 34 | 35 | # Replace Net::HTTP with our failing subclass 36 | ::Net.class_eval do 37 | remove_const(:HTTP) 38 | const_set(:HTTP, ::Fail) 39 | end 40 | -------------------------------------------------------------------------------- /lib/bundler/feature_flag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class FeatureFlag 4 | def self.settings_flag(flag, &default) 5 | unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) 6 | raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" 7 | end 8 | define_method("#{flag}?") do 9 | value = Bundler.settings[flag] 10 | value = instance_eval(&default) if value.nil? && !default.nil? 11 | value 12 | end 13 | end 14 | 15 | (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } 16 | 17 | settings_flag(:allow_offline_install) { bundler_2_mode? } 18 | settings_flag(:only_update_to_newer_versions) { bundler_2_mode? } 19 | settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } 20 | 21 | def initialize(bundler_version) 22 | @bundler_version = Gem::Version.create(bundler_version) 23 | end 24 | 25 | def major_version 26 | @bundler_version.segments.first 27 | end 28 | private :major_version 29 | 30 | class << self; private :settings_flag; end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/bundler/cli/plugin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/vendored_thor" 3 | module Bundler 4 | class CLI::Plugin < Thor 5 | desc "install PLUGINS", "Install the plugin from the source" 6 | long_desc <<-D 7 | 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 8 | D 9 | method_option "source", :type => :string, :default => nil, :banner => 10 | "URL of the RubyGems source to fetch the plugin from" 11 | method_option "version", :type => :string, :default => nil, :banner => 12 | "The version of the plugin to fetch" 13 | method_option "git", :type => :string, :default => nil, :banner => 14 | "URL of the git repo to fetch from" 15 | method_option "branch", :type => :string, :default => nil, :banner => 16 | "The git branch to checkout" 17 | method_option "ref", :type => :string, :default => nil, :banner => 18 | "The git revision to check out" 19 | def install(*plugins) 20 | Bundler::Plugin.install(plugins, options) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /doc/documentation/VISION.md: -------------------------------------------------------------------------------- 1 | # Documentation vision 2 | 3 | Currently, documentation for using Bundler is spread across two places: 4 | 5 | 1. built-in `help` (including usage information and man pages) 6 | 2. [Bundler documentation site](http://bundler.io) 7 | 8 | Additional documentation about using Bundler to publish gems can also be found on the [RubyGems guides](http://guides.rubygems.org/). 9 | 10 | ## Goals 11 | 12 | Bundler documentation should provide users with assistance: 13 | 14 | 1. Installing Bundler 15 | 2. Using Bundler to manage an application's dependencies 16 | 3. Using Bundler to create, package, and publish gems 17 | 18 | Our goal is to provide three types of documentation: 19 | 20 | * High level overviews that provide topical guidance 21 | * Step-by-step tutorials 22 | * Command-specific reference material for the CLI 23 | 24 | Additionally, this documentation should be readily available in a logical place and easy to follow. 25 | 26 | Someday, we'd like to create deep-dive reference material about the inner workings of Bundler. However, while this is part of our overall vision for Bundler documentation, it is not the focus of our current work. 27 | -------------------------------------------------------------------------------- /bin/with_rubygems: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "pathname" 5 | 6 | def run(*cmd) 7 | return if system(*cmd) 8 | raise "Running `#{cmd.join(" ")}` failed" 9 | end 10 | 11 | version = ENV.delete("RGV") 12 | rubygems_path = Pathname.new(__FILE__).join("../../tmp/rubygems").expand_path 13 | unless rubygems_path.directory? 14 | rubygems_path.parent.mkpath unless rubygems_path.directory? 15 | run("git", "clone", "https://github.com/rubygems/rubygems.git", rubygems_path.to_s) 16 | end 17 | Dir.chdir(rubygems_path) do 18 | version = "v#{version}" if version =~ /\A\d/ 19 | run("git", "checkout", version, "--quiet") 20 | end if version 21 | 22 | rubygems_lib = rubygems_path + "lib" 23 | ENV["RUBYOPT"] = %(-I#{rubygems_lib} #{ENV["RUBYOPT"]}) 24 | 25 | if $0 != __FILE__ 26 | ARGV.unshift($0) 27 | elsif cmd = ARGV.first 28 | possible_dirs = [ 29 | Pathname.new(__FILE__) + "..", 30 | Pathname.new(__FILE__) + "../../exe", 31 | rubygems_path + "bin", 32 | ] 33 | cmd = possible_dirs.map do |dir| 34 | dir.join(cmd).expand_path 35 | end.find(&:file?) 36 | ARGV[0] = cmd.to_s if cmd 37 | end 38 | 39 | exec(*ARGV) 40 | -------------------------------------------------------------------------------- /spec/install/force_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install" do 5 | describe "with --force" do 6 | before :each do 7 | gemfile <<-G 8 | source "file://#{gem_repo1}" 9 | gem "rack" 10 | G 11 | end 12 | 13 | it "re-installs installed gems" do 14 | rack_lib = default_bundle_path("gems/rack-1.0.0/lib/rack.rb") 15 | 16 | bundle "install" 17 | rack_lib.open("w") {|f| f.write("blah blah blah") } 18 | bundle "install --force" 19 | 20 | expect(exitstatus).to eq(0) if exitstatus 21 | expect(out).to include "Using bundler" 22 | expect(out).to include "Installing rack 1.0.0" 23 | expect(rack_lib.open(&:read)).to eq("RACK = '1.0.0'\n") 24 | expect(the_bundle).to include_gems "rack 1.0.0" 25 | end 26 | 27 | it "works on first bundle install" do 28 | bundle "install --force" 29 | 30 | expect(exitstatus).to eq(0) if exitstatus 31 | expect(out).to include "Using bundler" 32 | expect(out).to include "Installing rack 1.0.0" 33 | expect(the_bundle).to include_gems "rack 1.0.0" 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/bundler/compact_index_client/updater_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "net/http" 4 | require "bundler/compact_index_client" 5 | require "bundler/compact_index_client/updater" 6 | 7 | RSpec.describe Bundler::CompactIndexClient::Updater do 8 | subject(:updater) { described_class.new(fetcher) } 9 | 10 | let(:fetcher) { double(:fetcher) } 11 | 12 | context "when the ETag header is missing" do 13 | # Regression test for https://github.com/bundler/bundler/issues/5463 14 | 15 | let(:response) { double(:response, :body => "") } 16 | let(:local_path) { Pathname("/tmp/localpath") } 17 | let(:remote_path) { double(:remote_path) } 18 | 19 | it "MisMatchedChecksumError is raised" do 20 | # Twice: #update retries on failure 21 | expect(response).to receive(:[]).with("Content-Encoding").twice { "" } 22 | expect(response).to receive(:[]).with("ETag").twice { nil } 23 | expect(fetcher).to receive(:call).twice { response } 24 | 25 | expect do 26 | updater.update(local_path, remote_path) 27 | end.to raise_error(Bundler::CompactIndexClient::Updater::MisMatchedChecksumError) 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/install/gemfile/install_if.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | describe "bundle install with install_if conditionals" do 5 | it "follows the install_if DSL" do 6 | install_gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | install_if(lambda { true }) do 9 | gem "activesupport", "2.3.5" 10 | end 11 | gem "thin", :install_if => false 12 | install_if(lambda { false }) do 13 | gem "foo" 14 | end 15 | gem "rack" 16 | G 17 | 18 | expect(the_bundle).to include_gems("rack 1.0", "activesupport 2.3.5") 19 | expect(the_bundle).not_to include_gems("thin") 20 | expect(the_bundle).not_to include_gems("foo") 21 | 22 | lockfile_should_be <<-L 23 | GEM 24 | remote: file:#{gem_repo1}/ 25 | specs: 26 | activesupport (2.3.5) 27 | foo (1.0) 28 | rack (1.0.0) 29 | thin (1.0) 30 | rack 31 | 32 | PLATFORMS 33 | ruby 34 | 35 | DEPENDENCIES 36 | activesupport (= 2.3.5) 37 | foo 38 | rack 39 | thin 40 | 41 | BUNDLED WITH 42 | #{Bundler::VERSION} 43 | L 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Portions copyright (c) 2010 Andre Arko 2 | Portions copyright (c) 2009 Engine Yard 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /lib/bundler/cli/pristine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | 4 | module Bundler 5 | class CLI::Pristine 6 | def run 7 | Bundler.load.specs.each do |spec| 8 | next if spec.name == "bundler" # Source::Rubygems doesn't install bundler 9 | 10 | gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" 11 | gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY 12 | 13 | case spec.source 14 | when Source::Rubygems 15 | cached_gem = spec.cache_file 16 | unless File.exist?(cached_gem) 17 | Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") 18 | next 19 | end 20 | 21 | FileUtils.rm_rf spec.full_gem_path 22 | spec.source.install(spec, :force => true) 23 | when Source::Git 24 | git_source = spec.source 25 | git_source.remote! 26 | git_source.install(spec, :force => true) 27 | else 28 | Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/LICENSE.txt.tt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) <%= Time.now.year %> <%= config[:author] %> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /spec/bundler/index_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::Index do 5 | let(:specs) { [] } 6 | subject { described_class.build {|i| i.use(specs) } } 7 | 8 | context "specs with a nil platform" do 9 | let(:spec) do 10 | Gem::Specification.new do |s| 11 | s.name = "json" 12 | s.version = "1.8.3" 13 | allow(s).to receive(:platform).and_return(nil) 14 | end 15 | end 16 | let(:specs) { [spec] } 17 | 18 | describe "#search_by_spec" do 19 | it "finds the spec when a nil platform is specified" do 20 | expect(subject.search(spec)).to eq([spec]) 21 | end 22 | 23 | it "finds the spec when a ruby platform is specified" do 24 | query = spec.dup.tap {|s| s.platform = "ruby" } 25 | expect(subject.search(query)).to eq([spec]) 26 | end 27 | end 28 | end 29 | 30 | context "with specs that include development dependencies" do 31 | let(:specs) { [*build_spec("a", "1.0.0") {|s| s.development("b", "~> 1.0") }] } 32 | 33 | it "does not include b in #dependency_names" do 34 | expect(subject.dependency_names).not_to include("b") 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/bundler/fetcher/base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Fetcher 4 | class Base 5 | attr_reader :downloader 6 | attr_reader :display_uri 7 | attr_reader :remote 8 | 9 | def initialize(downloader, remote, display_uri) 10 | raise "Abstract class" if self.class == Base 11 | @downloader = downloader 12 | @remote = remote 13 | @display_uri = display_uri 14 | end 15 | 16 | def remote_uri 17 | @remote.uri 18 | end 19 | 20 | def fetch_uri 21 | @fetch_uri ||= begin 22 | if remote_uri.host == "rubygems.org" 23 | uri = remote_uri.dup 24 | uri.host = "index.rubygems.org" 25 | uri 26 | else 27 | remote_uri 28 | end 29 | end 30 | end 31 | 32 | def available? 33 | true 34 | end 35 | 36 | def api_fetcher? 37 | false 38 | end 39 | 40 | private 41 | 42 | def log_specs(debug_msg) 43 | if Bundler.ui.debug? 44 | Bundler.ui.debug debug_msg 45 | else 46 | Bundler.ui.info ".", false 47 | end 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/commands/init_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle init" do 5 | it "generates a Gemfile" do 6 | bundle :init 7 | expect(bundled_app("Gemfile")).to exist 8 | end 9 | 10 | it "does not change existing Gemfiles" do 11 | gemfile <<-G 12 | gem "rails" 13 | G 14 | 15 | expect do 16 | bundle :init 17 | end.not_to change { File.read(bundled_app("Gemfile")) } 18 | end 19 | 20 | it "should generate from an existing gemspec" do 21 | spec_file = tmp.join("test.gemspec") 22 | File.open(spec_file, "w") do |file| 23 | file << <<-S 24 | Gem::Specification.new do |s| 25 | s.name = 'test' 26 | s.add_dependency 'rack', '= 1.0.1' 27 | s.add_development_dependency 'rspec', '1.2' 28 | end 29 | S 30 | end 31 | 32 | bundle :init, :gemspec => spec_file 33 | 34 | gemfile = bundled_app("Gemfile").read 35 | expect(gemfile).to match(%r{source 'https://rubygems.org'}) 36 | expect(gemfile.scan(/gem "rack", "= 1.0.1"/).size).to eq(1) 37 | expect(gemfile.scan(/gem "rspec", "= 1.2"/).size).to eq(1) 38 | expect(gemfile.scan(/group :development/).size).to eq(1) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/bundler/cli/cache.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Cache 4 | attr_reader :options 5 | def initialize(options) 6 | @options = options 7 | end 8 | 9 | def run 10 | Bundler.definition.validate_runtime! 11 | Bundler.definition.resolve_with_cache! 12 | setup_cache_all 13 | Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms") 14 | Bundler.load.cache 15 | Bundler.settings[:no_prune] = true if options["no-prune"] 16 | Bundler.load.lock 17 | rescue GemNotFound => e 18 | Bundler.ui.error(e.message) 19 | Bundler.ui.warn "Run `bundle install` to install missing gems." 20 | exit 1 21 | end 22 | 23 | private 24 | 25 | def setup_cache_all 26 | Bundler.settings[:cache_all] = options[:all] if options.key?("all") 27 | 28 | if Bundler.definition.has_local_dependencies? && !Bundler.settings[:cache_all] 29 | Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ 30 | "to package them as well, please pass the --all flag. This will be the default " \ 31 | "on Bundler 2.0." 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/install/prereleases_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install" do 5 | describe "when prerelease gems are available" do 6 | it "finds prereleases" do 7 | install_gemfile <<-G 8 | source "file://#{gem_repo1}" 9 | gem "not_released" 10 | G 11 | expect(the_bundle).to include_gems "not_released 1.0.pre" 12 | end 13 | 14 | it "uses regular releases if available" do 15 | install_gemfile <<-G 16 | source "file://#{gem_repo1}" 17 | gem "has_prerelease" 18 | G 19 | expect(the_bundle).to include_gems "has_prerelease 1.0" 20 | end 21 | 22 | it "uses prereleases if requested" do 23 | install_gemfile <<-G 24 | source "file://#{gem_repo1}" 25 | gem "has_prerelease", "1.1.pre" 26 | G 27 | expect(the_bundle).to include_gems "has_prerelease 1.1.pre" 28 | end 29 | end 30 | 31 | describe "when prerelease gems are not available" do 32 | it "still works" do 33 | build_repo3 34 | install_gemfile <<-G 35 | source "file://#{gem_repo3}" 36 | gem "rack" 37 | G 38 | 39 | expect(the_bundle).to include_gems "rack 1.0" 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/bundler/vendor/postit/lib/postit/environment.rb: -------------------------------------------------------------------------------- 1 | require 'bundler/vendor/postit/lib/postit/parser' 2 | 3 | module BundlerVendoredPostIt::PostIt 4 | class Environment 5 | def initialize(argv) 6 | @argv = argv 7 | end 8 | 9 | def env_var_version 10 | ENV['BUNDLER_VERSION'] 11 | end 12 | 13 | def cli_arg_version 14 | return unless str = @argv.first 15 | str = str.dup.force_encoding('BINARY') if str.respond_to?(:force_encoding) 16 | if Gem::Version.correct?(str) 17 | @argv.shift 18 | str 19 | end 20 | end 21 | 22 | def gemfile 23 | ENV['BUNDLE_GEMFILE'] || 'Gemfile' 24 | end 25 | 26 | def lockfile 27 | File.expand_path case File.basename(gemfile) 28 | when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile) 29 | else "#{gemfile}.lock" 30 | end 31 | end 32 | 33 | def lockfile_version 34 | BundlerVendoredPostIt::PostIt::Parser.new(lockfile).parse 35 | end 36 | 37 | def bundler_version 38 | @bundler_version ||= begin 39 | env_var_version || cli_arg_version || 40 | lockfile_version || "#{Gem::Requirement.default}.a" 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/bundler/cli/console.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Console 4 | attr_reader :options, :group 5 | def initialize(options, group) 6 | @options = options 7 | @group = group 8 | end 9 | 10 | def run 11 | Bundler::SharedHelpers.major_deprecation "bundle console will be replaced " \ 12 | "by `bin/console` generated by `bundle gem `" 13 | 14 | group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require 15 | ARGV.clear 16 | 17 | console = get_console(Bundler.settings[:console] || "irb") 18 | console.start 19 | end 20 | 21 | def get_console(name) 22 | require name 23 | get_constant(name) 24 | rescue LoadError 25 | Bundler.ui.error "Couldn't load console #{name}, falling back to irb" 26 | require "irb" 27 | get_constant("irb") 28 | end 29 | 30 | def get_constant(name) 31 | const_name = { 32 | "pry" => :Pry, 33 | "ripl" => :Ripl, 34 | "irb" => :IRB, 35 | }[name] 36 | Object.const_get(const_name) 37 | rescue NameError 38 | Bundler.ui.error "Could not find constant #{const_name}" 39 | exit 1 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/runtime/gem_tasks_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "require 'bundler/gem_tasks'" do 5 | before :each do 6 | bundled_app("foo.gemspec").open("w") do |f| 7 | f.write <<-GEMSPEC 8 | Gem::Specification.new do |s| 9 | s.name = "foo" 10 | end 11 | GEMSPEC 12 | end 13 | bundled_app("Rakefile").open("w") do |f| 14 | f.write <<-RAKEFILE 15 | $:.unshift("#{bundler_path}") 16 | require "bundler/gem_tasks" 17 | RAKEFILE 18 | end 19 | end 20 | 21 | it "includes the relevant tasks" do 22 | with_gem_path_as(Spec::Path.base_system_gems.to_s) do 23 | sys_exec "ruby -S rake -T" 24 | end 25 | 26 | expect(err).to eq("") 27 | expected_tasks = [ 28 | "rake build", 29 | "rake clean", 30 | "rake clobber", 31 | "rake install", 32 | "rake release[remote]", 33 | ] 34 | tasks = out.lines.to_a.map {|s| s.split("#").first.strip } 35 | expect(tasks & expected_tasks).to eq(expected_tasks) 36 | expect(exitstatus).to eq(0) if exitstatus 37 | end 38 | 39 | it "adds 'pkg' to rake/clean's CLOBBER" do 40 | require "bundler/gem_tasks" 41 | expect(CLOBBER).to include("pkg") 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_concurrent_download.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexConcurrentDownload < CompactIndexAPI 7 | get "/versions" do 8 | versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", 9 | "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions") 10 | 11 | # Verify the original (empty) content hasn't been deleted, e.g. on a retry 12 | File.read(versions) == "" || raise("Original file should be present and empty") 13 | 14 | # Verify this is only requested once for a partial download 15 | env["HTTP_RANGE"] || raise("Missing Range header for expected partial download") 16 | 17 | # Overwrite the file in parallel, which should be then overwritten 18 | # after a successful download to prevent corruption 19 | File.open(versions, "w") {|f| f.puts "another process" } 20 | 21 | etag_response do 22 | file = tmp("versions.list") 23 | file.delete if file.file? 24 | file = CompactIndex::VersionsFile.new(file.to_s) 25 | file.create(gems) 26 | file.contents 27 | end 28 | end 29 | end 30 | 31 | Artifice.activate_with(CompactIndexConcurrentDownload) 32 | -------------------------------------------------------------------------------- /exe/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # Exit cleanly from an early interrupt 5 | Signal.trap("INT") do 6 | Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) 7 | exit 1 8 | end 9 | 10 | update = "update".start_with?(ARGV.first || " ") && ARGV.find {|a| a.start_with?("--bundler") } 11 | update &&= update =~ /--bundler(?:=(.+))?/ && $1 || "> 0.a" 12 | ENV["BUNDLER_VERSION"] = update if update 13 | require "bundler/postit_trampoline" 14 | 15 | require "bundler" 16 | # Check if an older version of bundler is installed 17 | $LOAD_PATH.each do |path| 18 | next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9 19 | err = String.new 20 | err << "Looks like you have a version of bundler that's older than 0.9.\n" 21 | err << "Please remove your old versions.\n" 22 | err << "An easy way to do this is by running `gem cleanup bundler`." 23 | abort(err) 24 | end 25 | 26 | require "bundler/friendly_errors" 27 | Bundler.with_friendly_errors do 28 | require "bundler/cli" 29 | 30 | # Allow any command to use --help flag to show help for that command 31 | help_flags = %w(--help -h) 32 | help_flag_used = ARGV.any? {|a| help_flags.include? a } 33 | args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV 34 | 35 | Bundler::CLI.start(args, :debug => true) 36 | end 37 | -------------------------------------------------------------------------------- /man/bundle-platform.ronn: -------------------------------------------------------------------------------- 1 | bundle-platform(1) -- Displays platform compatibility information 2 | ================================================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle platform` [--ruby] 7 | 8 | ## DESCRIPTION 9 | 10 | `platform` will display information from your Gemfile, Gemfile.lock, and Ruby 11 | VM about your platform. 12 | 13 | For instance, using this Gemfile(5): 14 | 15 | source "https://rubygems.org" 16 | 17 | ruby "1.9.3" 18 | 19 | gem "rack" 20 | 21 | If you run `bundle platform` on Ruby 1.9.3, it will display the following output: 22 | 23 | Your platform is: x86_64-linux 24 | 25 | Your app has gems that work on these platforms: 26 | * ruby 27 | 28 | Your Gemfile specifies a Ruby version requirement: 29 | * ruby 1.9.3 30 | 31 | Your current platform satisfies the Ruby version requirement. 32 | 33 | `platform` will list all the platforms in your `Gemfile.lock` as well as the 34 | `ruby` directive if applicable from your Gemfile(5). It will also let you know 35 | if the `ruby` directive requirement has been met. If `ruby` directive doesn't 36 | match the running Ruby VM, it will tell you what part does not. 37 | 38 | ## OPTIONS 39 | 40 | * `--ruby`: 41 | It will display the ruby directive information, so you don't have to 42 | parse it from the Gemfile(5). 43 | -------------------------------------------------------------------------------- /spec/bundler/plugin/dsl_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::Plugin::DSL do 5 | DSL = Bundler::Plugin::DSL 6 | 7 | subject(:dsl) { Bundler::Plugin::DSL.new } 8 | 9 | before do 10 | allow(Bundler).to receive(:root) { Pathname.new "/" } 11 | end 12 | 13 | describe "it ignores only the methods defined in Bundler::Dsl" do 14 | it "doesn't raises error for Dsl methods" do 15 | expect { dsl.install_if }.not_to raise_error 16 | end 17 | 18 | it "raises error for other methods" do 19 | expect { dsl.no_method }.to raise_error(DSL::PluginGemfileError) 20 | end 21 | end 22 | 23 | describe "source block" do 24 | it "adds #source with :type to list and also inferred_plugins list" do 25 | expect(dsl).to receive(:plugin).with("bundler-source-news").once 26 | 27 | dsl.source("some_random_url", :type => "news") {} 28 | 29 | expect(dsl.inferred_plugins).to eq(["bundler-source-news"]) 30 | end 31 | 32 | it "registers a source type plugin only once for multiple declataions" do 33 | expect(dsl).to receive(:plugin).with("bundler-source-news").and_call_original.once 34 | 35 | dsl.source("some_random_url", :type => "news") {} 36 | dsl.source("another_random_url", :type => "news") {} 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/bundler/installer/gem_installer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/installer/gem_installer" 4 | 5 | RSpec.describe Bundler::GemInstaller do 6 | let(:installer) { instance_double("Installer") } 7 | let(:spec_source) { instance_double("SpecSource") } 8 | let(:spec) { instance_double("Specification", :name => "dummy", :version => "0.0.1", :loaded_from => "dummy", :source => spec_source) } 9 | 10 | subject { described_class.new(spec, installer) } 11 | 12 | context "spec_settings is nil" do 13 | it "invokes install method with empty build_args", :rubygems => ">= 2" do 14 | allow(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => []) 15 | subject.install_from_spec 16 | end 17 | end 18 | 19 | context "spec_settings is build option" do 20 | it "invokes install method with build_args", :rubygems => ">= 2" do 21 | allow(Bundler.settings).to receive(:[]).with(:bin) 22 | allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy") 23 | allow(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy"]) 24 | subject.install_from_spec 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/bundler/ui_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe Bundler::UI do 5 | describe Bundler::UI::Silent do 6 | it "has the same instance methods as Shell", :ruby => ">= 1.9" do 7 | shell = Bundler::UI::Shell 8 | methods = proc do |cls| 9 | cls.instance_methods.map do |i| 10 | m = shell.instance_method(i) 11 | [i, m.parameters] 12 | end.sort_by(&:first) 13 | end 14 | expect(methods.call(described_class)).to eq(methods.call(shell)) 15 | end 16 | 17 | it "has the same instance class as Shell", :ruby => ">= 1.9" do 18 | shell = Bundler::UI::Shell 19 | methods = proc do |cls| 20 | cls.methods.map do |i| 21 | m = shell.method(i) 22 | [i, m.parameters] 23 | end.sort_by(&:first) 24 | end 25 | expect(methods.call(described_class)).to eq(methods.call(shell)) 26 | end 27 | end 28 | 29 | describe Bundler::UI::Shell do 30 | let(:options) { {} } 31 | subject { described_class.new(options) } 32 | describe "debug?" do 33 | it "returns a boolean" do 34 | subject.level = :debug 35 | expect(subject.debug?).to eq(true) 36 | 37 | subject.level = :error 38 | expect(subject.debug?).to eq(false) 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/support/artifice/windows.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../../path.rb", __FILE__) 3 | include Spec::Path 4 | 5 | $LOAD_PATH.unshift Dir[base_system_gems.join("gems/artifice*/lib")].first.to_s 6 | $LOAD_PATH.unshift(*Dir[base_system_gems.join("gems/rack-*/lib")]) 7 | $LOAD_PATH.unshift Dir[base_system_gems.join("gems/tilt*/lib")].first.to_s 8 | $LOAD_PATH.unshift Dir[base_system_gems.join("gems/sinatra*/lib")].first.to_s 9 | require "artifice" 10 | require "sinatra/base" 11 | 12 | Artifice.deactivate 13 | 14 | class Windows < Sinatra::Base 15 | set :raise_errors, true 16 | set :show_exceptions, false 17 | 18 | helpers do 19 | def gem_repo 20 | Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"] || Spec::Path.gem_repo1) 21 | end 22 | end 23 | 24 | files = ["specs.4.8.gz", 25 | "prerelease_specs.4.8.gz", 26 | "quick/Marshal.4.8/rcov-1.0-mswin32.gemspec.rz", 27 | "gems/rcov-1.0-mswin32.gem"] 28 | 29 | files.each do |file| 30 | get "/#{file}" do 31 | File.read gem_repo.join(file) 32 | end 33 | end 34 | 35 | get "/gems/rcov-1.0-x86-mswin32.gem" do 36 | halt 404 37 | end 38 | 39 | get "/api/v1/dependencies" do 40 | halt 404 41 | end 42 | 43 | get "/versions" do 44 | halt 500 45 | end 46 | end 47 | 48 | Artifice.activate_with(Windows) 49 | -------------------------------------------------------------------------------- /lib/bundler/ui/silent.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | module UI 4 | class Silent 5 | attr_writer :shell 6 | 7 | def initialize 8 | @warnings = [] 9 | end 10 | 11 | def add_color(string, color) 12 | string 13 | end 14 | 15 | def info(message, newline = nil) 16 | end 17 | 18 | def confirm(message, newline = nil) 19 | end 20 | 21 | def warn(message, newline = nil) 22 | @warnings |= [message] 23 | end 24 | 25 | def error(message, newline = nil) 26 | end 27 | 28 | def debug(message, newline = nil) 29 | end 30 | 31 | def debug? 32 | false 33 | end 34 | 35 | def quiet? 36 | false 37 | end 38 | 39 | def ask(message) 40 | end 41 | 42 | def yes?(msg) 43 | raise "Cannot ask yes? with a silent shell" 44 | end 45 | 46 | def no? 47 | raise "Cannot ask no? with a silent shell" 48 | end 49 | 50 | def level=(name) 51 | end 52 | 53 | def level(name = nil) 54 | end 55 | 56 | def trace(message, newline = nil, force = false) 57 | end 58 | 59 | def silence 60 | yield 61 | end 62 | 63 | def unprinted_warnings 64 | @warnings 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG 3 | A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 4 | b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw 5 | MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i 6 | YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT 7 | aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ 8 | jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp 9 | xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 10 | 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG 11 | snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ 12 | U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 13 | 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E 14 | BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B 15 | AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz 16 | yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 17 | 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP 18 | AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad 19 | DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME 20 | HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /spec/support/hax.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rubygems" 3 | 4 | module Gem 5 | class Platform 6 | @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) if ENV["BUNDLER_SPEC_PLATFORM"] 7 | end 8 | @platforms = [Gem::Platform::RUBY, Gem::Platform.local] 9 | end 10 | 11 | if ENV["BUNDLER_SPEC_VERSION"] 12 | module Bundler 13 | remove_const(:VERSION) if const_defined?(:VERSION) 14 | VERSION = ENV["BUNDLER_SPEC_VERSION"].dup 15 | end 16 | end 17 | 18 | if ENV["BUNDLER_SPEC_WINDOWS"] == "true" 19 | require "bundler/constants" 20 | 21 | module Bundler 22 | remove_const :WINDOWS if defined?(WINDOWS) 23 | WINDOWS = true 24 | end 25 | end 26 | 27 | class Object 28 | if ENV["BUNDLER_SPEC_RUBY_ENGINE"] 29 | if defined?(RUBY_ENGINE) && RUBY_ENGINE != "jruby" && ENV["BUNDLER_SPEC_RUBY_ENGINE"] == "jruby" 30 | begin 31 | # this has to be done up front because psych will try to load a .jar 32 | # if it thinks its on jruby 33 | require "psych" 34 | rescue LoadError 35 | nil 36 | end 37 | end 38 | 39 | remove_const :RUBY_ENGINE if defined?(RUBY_ENGINE) 40 | RUBY_ENGINE = ENV["BUNDLER_SPEC_RUBY_ENGINE"] 41 | 42 | if RUBY_ENGINE == "jruby" 43 | remove_const :JRUBY_VERSION if defined?(JRUBY_VERSION) 44 | JRUBY_VERSION = ENV["BUNDLER_SPEC_RUBY_ENGINE_VERSION"] 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/install/gems/mirror_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install with a mirror configured" do 5 | describe "when the mirror does not match the gem source" do 6 | before :each do 7 | gemfile <<-G 8 | source "file://#{gem_repo1}" 9 | 10 | gem "rack" 11 | G 12 | bundle "config --local mirror.http://gems.example.org http://gem-mirror.example.org" 13 | end 14 | 15 | it "installs from the normal location" do 16 | bundle :install 17 | expect(out).to include("Fetching source index from file:#{gem_repo1}") 18 | expect(the_bundle).to include_gems "rack 1.0" 19 | end 20 | end 21 | 22 | describe "when the gem source matches a configured mirror" do 23 | before :each do 24 | gemfile <<-G 25 | # This source is bogus and doesn't have the gem we're looking for 26 | source "file://#{gem_repo2}" 27 | 28 | gem "rack" 29 | G 30 | bundle "config --local mirror.file://#{gem_repo2} file://#{gem_repo1}" 31 | end 32 | 33 | it "installs the gem from the mirror" do 34 | bundle :install 35 | expect(out).to include("Fetching source index from file:#{gem_repo1}") 36 | expect(out).not_to include("Fetching source index from file:#{gem_repo2}") 37 | expect(the_bundle).to include_gems "rack 1.0" 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/bundler/uri_credentials_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | module URICredentialsFilter 4 | module_function 5 | 6 | def credential_filtered_uri(uri_to_anonymize) 7 | return uri_to_anonymize if uri_to_anonymize.nil? 8 | uri = uri_to_anonymize.dup 9 | uri = URI(uri.to_s) unless uri.is_a?(URI) 10 | if uri.userinfo 11 | # oauth authentication 12 | if uri.password == "x-oauth-basic" || uri.password == "x" 13 | # URI as string does not display with password if no user is set 14 | oauth_designation = uri.password 15 | uri.user = oauth_designation 16 | end 17 | uri.password = nil 18 | end 19 | return uri if uri_to_anonymize.is_a?(URI) 20 | return uri.to_s if uri_to_anonymize.is_a?(String) 21 | rescue URI::InvalidURIError # uri is not canonical uri scheme 22 | uri 23 | end 24 | 25 | def credential_filtered_string(str_to_filter, uri) 26 | return str_to_filter if uri.nil? || str_to_filter.nil? 27 | str_with_no_credentials = str_to_filter.dup 28 | anonymous_uri_str = credential_filtered_uri(uri).to_s 29 | uri_str = uri.to_s 30 | if anonymous_uri_str != uri_str 31 | str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) 32 | end 33 | str_with_no_credentials 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' 3 | module Bundler::Molinillo 4 | class DependencyGraph 5 | # @!visibility private 6 | # @see DependencyGraph#set_payload 7 | class SetPayload < Action # :nodoc: 8 | # @!group Action 9 | 10 | # (see Action.action_name) 11 | def self.action_name 12 | :set_payload 13 | end 14 | 15 | # (see Action#up) 16 | def up(graph) 17 | vertex = graph.vertex_named(name) 18 | @old_payload = vertex.payload 19 | vertex.payload = payload 20 | end 21 | 22 | # (see Action#down) 23 | def down(graph) 24 | graph.vertex_named(name).payload = @old_payload 25 | end 26 | 27 | # @!group SetPayload 28 | 29 | # @return [String] the name of the vertex 30 | attr_reader :name 31 | 32 | # @return [Object] the payload for the vertex 33 | attr_reader :payload 34 | 35 | # Initialize an action to add set the payload for a vertex in a dependency 36 | # graph 37 | # @param [String] name the name of the vertex 38 | # @param [Object] payload the payload for the vertex 39 | def initialize(name, payload) 40 | @name = name 41 | @payload = payload 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/install/git_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install" do 5 | context "git sources" do 6 | it "displays the revision hash of the gem repository" do 7 | build_git "foo", "1.0", :path => lib_path("foo") 8 | 9 | install_gemfile <<-G 10 | gem "foo", :git => "#{lib_path("foo")}" 11 | G 12 | 13 | bundle :install 14 | expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at master@#{revision_for(lib_path("foo"))[0..6]})") 15 | expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}" 16 | end 17 | 18 | it "should check out git repos that are missing but not being installed" do 19 | build_git "foo" 20 | 21 | gemfile <<-G 22 | gem "foo", :git => "file://#{lib_path("foo-1.0")}", :group => :development 23 | G 24 | 25 | lockfile <<-L 26 | GIT 27 | remote: file://#{lib_path("foo-1.0")} 28 | specs: 29 | foo (1.0) 30 | 31 | PLATFORMS 32 | ruby 33 | 34 | DEPENDENCIES 35 | foo! 36 | L 37 | 38 | bundle "install --path=vendor/bundle --without development" 39 | 40 | expect(out).to include("Bundle complete!") 41 | expect(vendored_gems("bundler/gems/foo-1.0-#{revision_for(lib_path("foo-1.0"))[0..11]}")).to be_directory 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/bundler/cli/binstubs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | 4 | module Bundler 5 | class CLI::Binstubs 6 | attr_reader :options, :gems 7 | def initialize(options, gems) 8 | @options = options 9 | @gems = gems 10 | end 11 | 12 | def run 13 | Bundler.definition.validate_runtime! 14 | Bundler.settings[:bin] = options["path"] if options["path"] 15 | Bundler.settings[:bin] = nil if options["path"] && options["path"].empty? 16 | installer = Installer.new(Bundler.root, Bundler.definition) 17 | 18 | if gems.empty? 19 | Bundler.ui.error "`bundle binstubs` needs at least one gem to run." 20 | exit 1 21 | end 22 | 23 | gems.each do |gem_name| 24 | spec = Bundler.definition.specs.find {|s| s.name == gem_name } 25 | unless spec 26 | raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( 27 | gem_name, Bundler.definition.specs 28 | ) 29 | end 30 | 31 | if spec.name == "bundler" 32 | Bundler.ui.warn "Sorry, Bundler can only be run via Rubygems." 33 | elsif options[:standalone] 34 | installer.generate_standalone_bundler_executable_stubs(spec) 35 | else 36 | installer.generate_bundler_executable_stubs(spec, :force => options[:force], :binstubs_cmd => true) 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Docs: Contributing and developing Bundler 2 | 3 | _If you're looking for documentation on how to use Bundler: visit [bundler.io](http://bundler.io/), or run `bundle help` from the command line. You may also be interested in [troubleshooting common issues](TROUBLESHOOTING.md) found when using Bundler._ 4 | 5 | Bundler welcomes contributions from *everyone*. While contributing, please follow the project [code of conduct](http://bundler.io/conduct.html), so that everyone can be included. 6 | 7 | If you'd like to help make Bundler better, you totally rock! Thanks for helping us make Bundler better. 8 | 9 | ## Contributing 10 | 11 | * [Overview & getting started](contributing/README.md) 12 | * [How you can help: your first contributions!](contributing/HOW_YOU_CAN_HELP.md) 13 | * [Bug triage](contributing/BUG_TRIAGE.md) 14 | * [Getting help](contributing/GETTING_HELP.md) 15 | * [Filing issues](contributing/ISSUES.md) 16 | * [Community](contributing/COMMUNITY.md) 17 | 18 | ## Development 19 | 20 | * [Overview](development/README.md) 21 | * [Development setup](development/SETUP.md) 22 | * [Submitting pull requests](development/PULL_REQUESTS.md) 23 | * [Adding new features](development/NEW_FEATURES.md) 24 | * [Releasing Bundler](development/RELEASING.md) 25 | 26 | ## Documentation 27 | 28 | * [Overview](documentation/README.md) 29 | * [Writing docs for man pages](documentation/WRITING.md) 30 | * [Documentation vision](documentation/VISION.md) 31 | -------------------------------------------------------------------------------- /lib/bundler/cli/issue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rbconfig" 4 | 5 | module Bundler 6 | class CLI::Issue 7 | def run 8 | Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") 9 | Did you find an issue with Bundler? Before filing a new issue, 10 | be sure to check out these resources: 11 | 12 | 1. Check out our troubleshooting guide for quick fixes to common issues: 13 | https://github.com/bundler/bundler/blob/master/doc/TROUBLESHOOTING.md 14 | 15 | 2. Instructions for common Bundler uses can be found on the documentation 16 | site: http://bundler.io/ 17 | 18 | 3. Information about each Bundler command can be found in the Bundler 19 | man pages: http://bundler.io/man/bundle.1.html 20 | 21 | Hopefully the troubleshooting steps above resolved your problem! If things 22 | still aren't working the way you expect them to, please let us know so 23 | that we can diagnose and help fix the problem you're having. Please 24 | view the Filing Issues guide for more information: 25 | https://github.com/bundler/bundler/blob/master/doc/contributing/ISSUES.md 26 | 27 | EOS 28 | 29 | Bundler.ui.info Bundler::Env.new.report 30 | 31 | Bundler.ui.info "\n## Bundle Doctor" 32 | doctor 33 | end 34 | 35 | def doctor 36 | require "bundler/cli/doctor" 37 | Bundler::CLI::Doctor.new({}).run 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/support/artifice/compact_index_extra_api.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require File.expand_path("../compact_index", __FILE__) 3 | 4 | Artifice.deactivate 5 | 6 | class CompactIndexExtraApi < CompactIndexAPI 7 | get "/extra/names" do 8 | etag_response do 9 | CompactIndex.names(gems(gem_repo4).map(&:name)) 10 | end 11 | end 12 | 13 | get "/extra/versions" do 14 | etag_response do 15 | file = tmp("versions.list") 16 | file.delete if file.file? 17 | file = CompactIndex::VersionsFile.new(file.to_s) 18 | file.create(gems(gem_repo4)) 19 | file.contents 20 | end 21 | end 22 | 23 | get "/extra/info/:name" do 24 | etag_response do 25 | gem = gems(gem_repo4).find {|g| g.name == params[:name] } 26 | CompactIndex.info(gem ? gem.versions : []) 27 | end 28 | end 29 | 30 | get "/extra/specs.4.8.gz" do 31 | File.read("#{gem_repo4}/specs.4.8.gz") 32 | end 33 | 34 | get "/extra/prerelease_specs.4.8.gz" do 35 | File.read("#{gem_repo4}/prerelease_specs.4.8.gz") 36 | end 37 | 38 | get "/extra/quick/Marshal.4.8/:id" do 39 | redirect "/extra/fetch/actual/gem/#{params[:id]}" 40 | end 41 | 42 | get "/extra/fetch/actual/gem/:id" do 43 | File.read("#{gem_repo4}/quick/Marshal.4.8/#{params[:id]}") 44 | end 45 | 46 | get "/extra/gems/:id" do 47 | File.read("#{gem_repo4}/gems/#{params[:id]}") 48 | end 49 | end 50 | 51 | Artifice.activate_with(CompactIndexExtraApi) 52 | -------------------------------------------------------------------------------- /doc/development/SETUP.md: -------------------------------------------------------------------------------- 1 | # Development setup 2 | 3 | Bundler doesn't use a Gemfile to list development dependencies, because when we tried it we couldn't tell if we were awake or it was just another level of dreams. To work on Bundler, you'll probably want to do a couple of things. 4 | 5 | 1. Install `groff-base` and `graphviz` packages using your package manager, e.g for ubuntu 6 | 7 | $ sudo apt-get install graphviz groff-base -y 8 | 9 | and for OS X (with brew installed) 10 | 11 | $ brew install graphviz homebrew/dupes/groff 12 | 13 | 2. Install Bundler's development dependencies 14 | 15 | $ bin/rake spec:deps 16 | 17 | 3. Run the test suite, to make sure things are working 18 | 19 | $ bin/rake spec 20 | 21 | 4. Set up a shell alias to run Bundler from your clone, e.g. a Bash alias: 22 | 23 | $ alias dbundle='BUNDLE_TRAMPOLINE_DISABLE=1 ruby -I /path/to/bundler/lib /path/to/bundler/exe/bundle' 24 | 25 | The `BUNDLE_TRAMPOLINE_DISABLE` environment variable ensures that the version of Bundler in `/path/to/bundler/lib` will be used. Without that environment setting, Bundler will automatically download, install, and run the version of Bundler listed in `Gemfile.lock`. With that set up, you can test changes you've made to Bundler by running `dbundle`, without interfering with the regular `bundle` command. 26 | 27 | ## Debugging with `pry` 28 | 29 | To dive into the code with Pry: `RUBYOPT=-rpry dbundle` to require pry and then run commands. 30 | -------------------------------------------------------------------------------- /spec/cache/platform_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle cache with multiple platforms" do 5 | before :each do 6 | gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | 9 | platforms :mri, :rbx do 10 | gem "rack", "1.0.0" 11 | end 12 | 13 | platforms :jruby do 14 | gem "activesupport", "2.3.5" 15 | end 16 | G 17 | 18 | lockfile <<-G 19 | GEM 20 | remote: file:#{gem_repo1}/ 21 | specs: 22 | rack (1.0.0) 23 | activesupport (2.3.5) 24 | 25 | PLATFORMS 26 | ruby 27 | java 28 | 29 | DEPENDENCIES 30 | rack (1.0.0) 31 | activesupport (2.3.5) 32 | G 33 | 34 | cache_gems "rack-1.0.0", "activesupport-2.3.5" 35 | end 36 | 37 | it "ensures that a successful bundle install does not delete gems for other platforms" do 38 | bundle "install" 39 | 40 | expect(exitstatus).to eq 0 if exitstatus 41 | 42 | expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist 43 | expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist 44 | end 45 | 46 | it "ensures that a successful bundle update does not delete gems for other platforms" do 47 | bundle "update" 48 | 49 | expect(exitstatus).to eq 0 if exitstatus 50 | 51 | expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist 52 | expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 5 | ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL 6 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 7 | LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug 8 | RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm 9 | +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW 10 | PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM 11 | xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB 12 | Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 13 | hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg 14 | EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF 15 | MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA 16 | FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec 17 | nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z 18 | eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF 19 | hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 20 | Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe 21 | vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep 22 | +OkuE6N36B9K 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /lib/bundler/cli/check.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Check 4 | attr_reader :options 5 | 6 | def initialize(options) 7 | @options = options 8 | end 9 | 10 | def run 11 | if options[:path] 12 | Bundler.settings[:path] = File.expand_path(options[:path]) 13 | Bundler.settings[:disable_shared_gems] = true 14 | end 15 | 16 | begin 17 | definition = Bundler.definition 18 | definition.validate_runtime! 19 | not_installed = definition.missing_specs 20 | rescue GemNotFound, VersionConflict 21 | Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." 22 | Bundler.ui.warn "Install missing gems with `bundle install`." 23 | exit 1 24 | end 25 | 26 | if not_installed.any? 27 | Bundler.ui.error "The following gems are missing" 28 | not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } 29 | Bundler.ui.warn "Install missing gems with `bundle install`" 30 | exit 1 31 | elsif !Bundler.default_lockfile.file? && Bundler.settings[:frozen] 32 | Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" 33 | exit 1 34 | else 35 | Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] 36 | Bundler.ui.info "The Gemfile's dependencies are satisfied" 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/realworld/dependency_api_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "gemcutter's dependency API", :realworld => true do 5 | context "when Gemcutter API takes too long to respond" do 6 | before do 7 | require_rack 8 | 9 | port = find_unused_port 10 | @server_uri = "http://127.0.0.1:#{port}" 11 | 12 | require File.expand_path("../../support/artifice/endpoint_timeout", __FILE__) 13 | require "thread" 14 | @t = Thread.new do 15 | server = Rack::Server.start(:app => EndpointTimeout, 16 | :Host => "0.0.0.0", 17 | :Port => port, 18 | :server => "webrick", 19 | :AccessLog => [], 20 | :Logger => Spec::SilentLogger.new) 21 | server.start 22 | end 23 | @t.run 24 | 25 | wait_for_server("127.0.0.1", port) 26 | end 27 | 28 | after do 29 | Artifice.deactivate 30 | @t.kill 31 | @t.join 32 | end 33 | 34 | it "times out and falls back on the modern index" do 35 | gemfile <<-G 36 | source "#{@server_uri}" 37 | gem "rack" 38 | 39 | old_v, $VERBOSE = $VERBOSE, nil 40 | Bundler::Fetcher.api_timeout = 1 41 | $VERBOSE = old_v 42 | G 43 | 44 | bundle :install 45 | expect(out).to include("Fetching source index from #{@server_uri}/") 46 | expect(the_bundle).to include_gems "rack 1.0.0" 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/bundler/cli/platform.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Platform 4 | attr_reader :options 5 | def initialize(options) 6 | @options = options 7 | end 8 | 9 | def run 10 | platforms, ruby_version = Bundler.ui.silence do 11 | locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version 12 | gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string 13 | [Bundler.definition.platforms.map {|p| "* #{p}" }, 14 | locked_ruby_version || gemfile_ruby_version] 15 | end 16 | output = [] 17 | 18 | if options[:ruby] 19 | if ruby_version 20 | output << ruby_version 21 | else 22 | output << "No ruby version specified" 23 | end 24 | else 25 | output << "Your platform is: #{RUBY_PLATFORM}" 26 | output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" 27 | 28 | if ruby_version 29 | output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" 30 | 31 | begin 32 | Bundler.definition.validate_runtime! 33 | output << "Your current platform satisfies the Ruby version requirement." 34 | rescue RubyVersionMismatch => e 35 | output << e.message 36 | end 37 | else 38 | output << "Your Gemfile does not specify a Ruby version requirement." 39 | end 40 | end 41 | 42 | Bundler.ui.info output.join("\n\n") 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /doc/contributing/COMMUNITY.md: -------------------------------------------------------------------------------- 1 | # Community 2 | 3 | Community is an important part of all we do. If you’d like to be part of the Bundler community, you can jump right in and start helping make Bundler better for everyone who uses it. 4 | 5 | It would be tremendously helpful to have more people answering questions about Bundler (and often simply about [Rubygems](https://github.com/rubygems/rubygems) or Ruby itself) in our [issue tracker](https://github.com/bundler/bundler/issues) or on [Stack Overflow](http://stackoverflow.com/questions/tagged/bundler). 6 | 7 | Additional documentation and explanation is always helpful, too. If you have any suggestions for the Bundler website [bundler.io](http://bundler.io), we would absolutely love it if you opened an issue or pull request on the [bundler-site](https://github.com/bundler/bundler-site) repository. 8 | 9 | Sharing your experiences and discoveries by writing them up is a valuable way to help others who have similar problems or experiences in the future. You can write a blog post, create an example and commit it to Github, take screenshots, or make videos. 10 | 11 | Publishing examples of how Bundler is used helps everyone, and we’ve discovered that people already use it in ways that we never imagined when we were writing it. If you’re still not sure what to write about, there are also several projects doing interesting things based on Bundler. They could probably use publicity too. 12 | 13 | Finally, all contributors to the Bundler project must agree to the contributor [code of conduct](http://bundler.io/conduct.html). By participating in this project you agree to abide by its terms. 14 | -------------------------------------------------------------------------------- /lib/bundler/cli/package.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class CLI::Package 4 | attr_reader :options 5 | 6 | def initialize(options) 7 | @options = options 8 | end 9 | 10 | def run 11 | Bundler.ui.level = "error" if options[:quiet] 12 | Bundler.settings[:path] = File.expand_path(options[:path]) if options[:path] 13 | Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms") 14 | Bundler.settings[:cache_path] = options["cache-path"] if options.key?("cache-path") 15 | 16 | setup_cache_all 17 | install 18 | 19 | # TODO: move cache contents here now that all bundles are locked 20 | custom_path = Pathname.new(options[:path]) if options[:path] 21 | Bundler.load.cache(custom_path) 22 | end 23 | 24 | private 25 | 26 | def install 27 | require "bundler/cli/install" 28 | options = self.options.dup 29 | if Bundler.settings[:cache_all_platforms] 30 | options["local"] = false 31 | options["update"] = true 32 | end 33 | Bundler::CLI::Install.new(options).run 34 | end 35 | 36 | def setup_cache_all 37 | Bundler.settings[:cache_all] = options[:all] if options.key?("all") 38 | 39 | if Bundler.definition.has_local_dependencies? && !Bundler.settings[:cache_all] 40 | Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ 41 | "to package them as well, please pass the --all flag. This will be the default " \ 42 | "on Bundler 2.0." 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/realworld/gemfile_source_header_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "thread" 4 | 5 | RSpec.describe "fetching dependencies with a mirrored source", :realworld => true, :rubygems => ">= 2.0" do 6 | let(:mirror) { "https://server.example.org" } 7 | let(:original) { "http://127.0.0.1:#{@port}" } 8 | 9 | before do 10 | setup_server 11 | bundle "config --local mirror.#{mirror} #{original}" 12 | end 13 | 14 | after do 15 | Artifice.deactivate 16 | @t.kill 17 | @t.join 18 | end 19 | 20 | it "sets the 'X-Gemfile-Source' header and bundles successfully" do 21 | gemfile <<-G 22 | source "#{mirror}" 23 | gem 'weakling' 24 | G 25 | 26 | bundle :install 27 | 28 | expect(out).to include("Installing weakling") 29 | expect(out).to include("Bundle complete") 30 | expect(the_bundle).to include_gems "weakling 0.0.3" 31 | end 32 | 33 | private 34 | 35 | def setup_server 36 | require_rack 37 | @port = find_unused_port 38 | @server_uri = "http://127.0.0.1:#{@port}" 39 | 40 | require File.expand_path("../../support/artifice/endpoint_mirror_source", __FILE__) 41 | 42 | @t = Thread.new do 43 | Rack::Server.start(:app => EndpointMirrorSource, 44 | :Host => "0.0.0.0", 45 | :Port => @port, 46 | :server => "webrick", 47 | :AccessLog => [], 48 | :Logger => Spec::SilentLogger.new) 49 | end.run 50 | 51 | wait_for_server("127.0.0.1", @port) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU 3 | MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs 4 | IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 5 | MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux 6 | FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h 7 | bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v 8 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt 9 | H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 10 | uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX 11 | mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX 12 | a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN 13 | E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 14 | WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD 15 | VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 16 | Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU 17 | cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx 18 | IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN 19 | AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH 20 | YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 21 | 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC 22 | Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX 23 | c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a 24 | mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /spec/install/binstubs_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install" do 5 | describe "when system_bindir is set" do 6 | # On OS X, Gem.bindir defaults to /usr/bin, so system_bindir is useful if 7 | # you want to avoid sudo installs for system gems with OS X's default ruby 8 | it "overrides Gem.bindir" do 9 | expect(Pathname.new("/usr/bin")).not_to be_writable unless Process.euid == 0 10 | gemfile <<-G 11 | require 'rubygems' 12 | def Gem.bindir; "/usr/bin"; end 13 | source "file://#{gem_repo1}" 14 | gem "rack" 15 | G 16 | 17 | config "BUNDLE_SYSTEM_BINDIR" => system_gem_path("altbin").to_s 18 | bundle :install 19 | expect(the_bundle).to include_gems "rack 1.0.0" 20 | expect(system_gem_path("altbin/rackup")).to exist 21 | end 22 | end 23 | 24 | describe "when multiple gems contain the same exe" do 25 | before do 26 | build_repo2 do 27 | build_gem "fake", "14" do |s| 28 | s.executables = "rackup" 29 | end 30 | end 31 | 32 | install_gemfile <<-G, :binstubs => true 33 | source "file://#{gem_repo2}" 34 | gem "fake" 35 | gem "rack" 36 | G 37 | end 38 | 39 | it "prints a deprecation notice" do 40 | bundle "config major_deprecations true" 41 | gembin("rackup") 42 | expect(out).to include("Bundler is using a binstub that was created for a different gem.") 43 | end 44 | 45 | it "loads the correct spec's executable" do 46 | gembin("rackup") 47 | expect(out).to eq("1.2") 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/bundler/gem_remote_fetcher.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "rubygems/remote_fetcher" 3 | 4 | module Bundler 5 | # Adds support for setting custom HTTP headers when fetching gems from the 6 | # server. 7 | # 8 | # TODO: Get rid of this when and if gemstash only supports RubyGems versions 9 | # that contain https://github.com/rubygems/rubygems/commit/3db265cc20b2f813. 10 | class GemRemoteFetcher < Gem::RemoteFetcher 11 | attr_accessor :headers 12 | 13 | # Extracted from RubyGems 2.4. 14 | def fetch_http(uri, last_modified = nil, head = false, depth = 0) 15 | fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get 16 | # beginning of change 17 | response = request uri, fetch_type, last_modified do |req| 18 | headers.each {|k, v| req.add_field(k, v) } if headers 19 | end 20 | # end of change 21 | 22 | case response 23 | when Net::HTTPOK, Net::HTTPNotModified then 24 | response.uri = uri if response.respond_to? :uri 25 | head ? response : response.body 26 | when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, 27 | Net::HTTPTemporaryRedirect then 28 | raise FetchError.new("too many redirects", uri) if depth > 10 29 | 30 | location = URI.parse response["Location"] 31 | 32 | if https?(uri) && !https?(location) 33 | raise FetchError.new("redirecting to non-https resource: #{location}", uri) 34 | end 35 | 36 | fetch_http(location, last_modified, head, depth + 1) 37 | else 38 | raise FetchError.new("bad response #{response.message} #{response.code}", uri) 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /bundler.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # frozen_string_literal: true 3 | lib = File.expand_path("../lib/", __FILE__) 4 | $:.unshift lib unless $:.include?(lib) 5 | require "bundler/version" 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "bundler" 9 | s.version = Bundler::VERSION 10 | s.license = "MIT" 11 | s.authors = [ 12 | "André Arko", "Samuel Giddins", "Chris Morris", "James Wen", "Tim Moore", 13 | "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", 14 | "Yehuda Katz" 15 | ] 16 | s.email = ["team@bundler.io"] 17 | s.homepage = "http://bundler.io" 18 | s.summary = "The best way to manage your application's dependencies" 19 | s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably" 20 | 21 | s.required_ruby_version = ">= 1.8.7" 22 | s.required_rubygems_version = ">= 1.3.6" 23 | 24 | s.add_development_dependency "automatiek", "~> 0.1.0" 25 | s.add_development_dependency "mustache", "0.99.6" 26 | s.add_development_dependency "rake", "~> 10.0" 27 | s.add_development_dependency "rdiscount", "~> 2.2" 28 | s.add_development_dependency "ronn", "~> 0.7.3" 29 | s.add_development_dependency "rspec", "~> 3.5" 30 | 31 | s.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) } 32 | # we don't check in man pages, but we need to ship them because 33 | # we use them to generate the long-form help for each command. 34 | s.files += Dir.glob("man/**/*") 35 | 36 | s.bindir = "exe" 37 | s.executables = %w(bundle bundler) 38 | s.require_paths = ["lib"] 39 | end 40 | -------------------------------------------------------------------------------- /exe/bundle_ruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | Signal.trap("INT") { exit 1 } 5 | 6 | require "bundler/errors" 7 | require "bundler/ruby_version" 8 | require "bundler/ruby_dsl" 9 | require "bundler/shared_helpers" 10 | 11 | module Bundler 12 | class Dsl 13 | include RubyDsl 14 | 15 | attr_accessor :ruby_version 16 | 17 | def initialize 18 | @ruby_version = nil 19 | end 20 | 21 | def eval_gemfile(gemfile, contents = nil) 22 | contents ||= File.open(gemfile, "rb", &:read) 23 | instance_eval(contents, gemfile.to_s, 1) 24 | rescue SyntaxError => e 25 | bt = e.message.split("\n")[1..-1] 26 | raise GemfileError, ["Gemfile syntax error:", *bt].join("\n") 27 | rescue ScriptError, RegexpError, NameError, ArgumentError => e 28 | e.backtrace[0] = "#{e.backtrace[0]}: #{e.message} (#{e.class})" 29 | STDERR.puts e.backtrace.join("\n ") 30 | raise GemfileError, "There was an error in your Gemfile," \ 31 | " and Bundler cannot continue." 32 | end 33 | 34 | def source(source, options = {}) 35 | end 36 | 37 | def gem(name, *args) 38 | end 39 | 40 | def group(*args) 41 | end 42 | end 43 | end 44 | 45 | Bundler::SharedHelpers.major_deprecation("the bundle_ruby executable has been removed in favor of `bundle platform --ruby`") 46 | 47 | dsl = Bundler::Dsl.new 48 | begin 49 | dsl.eval_gemfile(Bundler::SharedHelpers.default_gemfile) 50 | ruby_version = dsl.ruby_version 51 | if ruby_version 52 | puts ruby_version 53 | else 54 | puts "No ruby version specified" 55 | end 56 | rescue Bundler::GemfileError => e 57 | puts e.message 58 | exit(-1) 59 | end 60 | -------------------------------------------------------------------------------- /spec/bundler/version_ranges_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/version_ranges" 4 | 5 | RSpec.describe Bundler::VersionRanges do 6 | describe ".empty?" do 7 | shared_examples_for "empty?" do |exp, *req| 8 | it "returns #{exp} for #{req}" do 9 | r = Gem::Requirement.new(*req) 10 | ranges = described_class.for(r) 11 | expect(described_class.empty?(*ranges)).to eq(exp), "expected `#{r}` #{exp ? "" : "not "}to be empty" 12 | end 13 | end 14 | 15 | include_examples "empty?", false 16 | include_examples "empty?", false, "!= 1" 17 | include_examples "empty?", false, "!= 1", "= 2" 18 | include_examples "empty?", false, "!= 1", "> 1" 19 | include_examples "empty?", false, "!= 1", ">= 1" 20 | include_examples "empty?", false, "= 1", ">= 0.1", "<= 1.1" 21 | include_examples "empty?", false, "= 1", ">= 1", "<= 1" 22 | include_examples "empty?", false, "= 1", "~> 1" 23 | include_examples "empty?", false, ">= 0.z", "= 0" 24 | include_examples "empty?", false, ">= 0" 25 | include_examples "empty?", false, ">= 1.0.0", "< 2.0.0" 26 | include_examples "empty?", false, "~> 1" 27 | include_examples "empty?", false, "~> 2.0", "~> 2.1" 28 | include_examples "empty?", true, "!= 1", "< 2", "> 2" 29 | include_examples "empty?", true, "!= 1", "<= 1", ">= 1" 30 | include_examples "empty?", true, "< 2", "> 2" 31 | include_examples "empty?", true, "= 1", "!= 1" 32 | include_examples "empty?", true, "= 1", "= 2" 33 | include_examples "empty?", true, "= 1", "~> 2" 34 | include_examples "empty?", true, ">= 0", "<= 0.a" 35 | include_examples "empty?", true, "~> 2.0", "~> 3" 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/bundler/cli/info.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | 4 | module Bundler 5 | class CLI::Info 6 | attr_reader :gem_name, :options 7 | def initialize(options, gem_name) 8 | @options = options 9 | @gem_name = gem_name 10 | end 11 | 12 | def run 13 | spec = spec_for_gem(gem_name) 14 | 15 | spec_not_found(gem_name) unless spec 16 | return print_gem_path(spec) if @options[:path] 17 | print_gem_info(spec) 18 | end 19 | 20 | private 21 | 22 | def spec_for_gem(gem_name) 23 | spec = Bundler.definition.specs.find {|s| s.name == gem_name } 24 | spec || default_gem_spec(gem_name) 25 | end 26 | 27 | def default_gem_spec(gem_name) 28 | return unless Gem::Specification.respond_to?(:find_all_by_name) 29 | gem_spec = Gem::Specification.find_all_by_name(gem_name).last 30 | return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? 31 | end 32 | 33 | def spec_not_found(gem_name) 34 | raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) 35 | end 36 | 37 | def print_gem_path(spec) 38 | Bundler.ui.info spec.full_gem_path 39 | end 40 | 41 | def print_gem_info(spec) 42 | gem_info = String.new 43 | gem_info << " * #{spec.name} (#{spec.version}#{spec.git_version})\n" 44 | gem_info << "\tSummary: #{spec.summary}\n" if spec.summary 45 | gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage 46 | gem_info << "\tPath: #{spec.full_gem_path}\n" 47 | gem_info << "\tDefault Gem: yes" if spec.respond_to?(:default_gem?) && spec.default_gem? 48 | Bundler.ui.info gem_info 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/commands/info_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle info" do 5 | context "info from specific gem in gemfile" do 6 | before do 7 | install_gemfile <<-G 8 | source "file://#{gem_repo1}" 9 | gem "rails" 10 | G 11 | end 12 | 13 | it "prints information about the current gem" do 14 | bundle "info rails" 15 | expect(out).to include "* rails (2.3.2) 16 | \tSummary: This is just a fake gem for testing 17 | \tHomepage: http://example.com" 18 | expect(out).to match(%r{Path\: .*\/rails\-2\.3\.2}) 19 | end 20 | 21 | context "given a gem that is not installed" do 22 | it "prints missing gem error" do 23 | bundle "info foo" 24 | expect(out).to eq "Could not find gem 'foo'." 25 | end 26 | end 27 | 28 | context "given a default gem shippped in ruby" do 29 | it "prints information about the default gem", :if => (RUBY_VERSION >= "2.0") do 30 | bundle "info rdoc" 31 | expect(out).to include("* rdoc") 32 | expect(out).to include("Default Gem: yes") 33 | end 34 | end 35 | 36 | context "when gem does not have homepage" do 37 | before do 38 | build_repo1 do 39 | build_gem "rails", "2.3.2" do |s| 40 | s.executables = "rails" 41 | s.summary = "Just another test gem" 42 | end 43 | end 44 | end 45 | 46 | it "excludes the homepage field from the output" do 47 | expect(out).to_not include("Homepage:") 48 | end 49 | end 50 | 51 | context "given --path option" do 52 | it "prints the path to the gem" do 53 | bundle "info rails" 54 | expect(out).to match(%r{.*\/rails\-2\.3\.2}) 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph' 3 | 4 | module Bundler::Molinillo 5 | # This class encapsulates a dependency resolver. 6 | # The resolver is responsible for determining which set of dependencies to 7 | # activate, with feedback from the {#specification_provider} 8 | # 9 | # 10 | class Resolver 11 | require 'bundler/vendor/molinillo/lib/molinillo/resolution' 12 | 13 | # @return [SpecificationProvider] the specification provider used 14 | # in the resolution process 15 | attr_reader :specification_provider 16 | 17 | # @return [UI] the UI module used to communicate back to the user 18 | # during the resolution process 19 | attr_reader :resolver_ui 20 | 21 | # Initializes a new resolver. 22 | # @param [SpecificationProvider] specification_provider 23 | # see {#specification_provider} 24 | # @param [UI] resolver_ui 25 | # see {#resolver_ui} 26 | def initialize(specification_provider, resolver_ui) 27 | @specification_provider = specification_provider 28 | @resolver_ui = resolver_ui 29 | end 30 | 31 | # Resolves the requested dependencies into a {DependencyGraph}, 32 | # locking to the base dependency graph (if specified) 33 | # @param [Array] requested an array of 'requested' dependencies that the 34 | # {#specification_provider} can understand 35 | # @param [DependencyGraph,nil] base the base dependency graph to which 36 | # dependencies should be 'locked' 37 | def resolve(requested, base = DependencyGraph.new) 38 | Resolution.new(specification_provider, 39 | resolver_ui, 40 | requested, 41 | base). 42 | resolve 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /doc/documentation/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | Code needs explanation, and sometimes those who know the code well have trouble explaining it to someone just getting into it. Because of that, we welcome documentation suggestions and patches from everyone, especially if they are brand new to using Bundler. 4 | 5 | Currently, Bundler has two main sources of documentation: 6 | 7 | 1. built-in `help` (including usage information and man pages) 8 | 2. [Bundler documentation site](http://bundler.io) 9 | 10 | If you have a suggestion or proposed change for [bundler.io](http://bundler.io), please open an issue or send a pull request to the [bundler-site](https://github.com/bundler/bundler-site) repository. 11 | 12 | Not sure where to write documentation? In general, follow these guidelines: 13 | 14 | * For an explanation of a specific Bundler command (ex: `bundle clean`): make changes to the man pages 15 | * For longer explanations or usage guides (ex: "Using Bundler with Rails"): create new documentation within the [bundler-site](https://github.com/bundler/bundler-site) repository 16 | 17 | If you are unsure where to begin, ping [@feministy](https://github.com/feministy) or [@indirect](https://github.com/indirect) in the Bundler Slack ([get an invite here](../contributing/GETTING_HELP.md)). 18 | 19 | ## [Writing docs for man pages)](WRITING.md) 20 | 21 | If you’d like to submit a patch to the man pages, you're in the right place! Details on editing and previewing changes to man pages can be found here. 22 | 23 | ## [Documentation vision](VISION.md) 24 | 25 | Just like Bundler, we have a grand plan (really, a wish list of sorts) for Bundler documentation. Preview our hopes and dreams for our documentation here. 26 | 27 | ## Translations 28 | 29 | We don't currently have any translations, but please reach out to us if you would like to help get this going. 30 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler::Molinillo 3 | # @!visibility private 4 | module Delegates 5 | # Delegates all {Bundler::Molinillo::ResolutionState} methods to a `#state` property. 6 | module ResolutionState 7 | # (see Bundler::Molinillo::ResolutionState#name) 8 | def name 9 | current_state = state || Bundler::Molinillo::ResolutionState.empty 10 | current_state.name 11 | end 12 | 13 | # (see Bundler::Molinillo::ResolutionState#requirements) 14 | def requirements 15 | current_state = state || Bundler::Molinillo::ResolutionState.empty 16 | current_state.requirements 17 | end 18 | 19 | # (see Bundler::Molinillo::ResolutionState#activated) 20 | def activated 21 | current_state = state || Bundler::Molinillo::ResolutionState.empty 22 | current_state.activated 23 | end 24 | 25 | # (see Bundler::Molinillo::ResolutionState#requirement) 26 | def requirement 27 | current_state = state || Bundler::Molinillo::ResolutionState.empty 28 | current_state.requirement 29 | end 30 | 31 | # (see Bundler::Molinillo::ResolutionState#possibilities) 32 | def possibilities 33 | current_state = state || Bundler::Molinillo::ResolutionState.empty 34 | current_state.possibilities 35 | end 36 | 37 | # (see Bundler::Molinillo::ResolutionState#depth) 38 | def depth 39 | current_state = state || Bundler::Molinillo::ResolutionState.empty 40 | current_state.depth 41 | end 42 | 43 | # (see Bundler::Molinillo::ResolutionState#conflicts) 44 | def conflicts 45 | current_state = state || Bundler::Molinillo::ResolutionState.empty 46 | current_state.conflicts 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/bundler/installer/parallel_installer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | require "bundler/installer/parallel_installer" 4 | 5 | RSpec.describe Bundler::ParallelInstaller do 6 | let(:installer) { instance_double("Installer") } 7 | let(:all_specs) { [] } 8 | let(:size) { 1 } 9 | let(:standalone) { false } 10 | let(:force) { false } 11 | 12 | subject { described_class.new(installer, all_specs, size, standalone, force) } 13 | 14 | context "when dependencies that are not on the overall installation list are the only ones not installed" do 15 | let(:all_specs) do 16 | [ 17 | build_spec("alpha", "1.0") {|s| s.runtime "a", "1" }, 18 | ].flatten 19 | end 20 | 21 | it "prints a warning" do 22 | expect(Bundler.ui).to receive(:warn).with(<<-W.strip) 23 | Your lockfile was created by an old Bundler that left some things out. 24 | You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile. 25 | The missing gems are: 26 | * a depended upon by alpha 27 | W 28 | subject.check_for_corrupt_lockfile 29 | end 30 | 31 | context "when size > 1" do 32 | let(:size) { 500 } 33 | 34 | it "prints a warning and sets size to 1" do 35 | expect(Bundler.ui).to receive(:warn).with(<<-W.strip) 36 | Your lockfile was created by an old Bundler that left some things out. 37 | Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing 500 at a time. 38 | You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile. 39 | The missing gems are: 40 | * a depended upon by alpha 41 | W 42 | subject.check_for_corrupt_lockfile 43 | expect(subject.size).to eq(1) 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/bundler/ssl_certs/certificate_manager.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "fileutils" 3 | require "net/https" 4 | require "openssl" 5 | 6 | module Bundler 7 | module SSLCerts 8 | class CertificateManager 9 | attr_reader :bundler_cert_path, :bundler_certs, :rubygems_certs 10 | 11 | def self.update_from!(rubygems_path) 12 | new(rubygems_path).update! 13 | end 14 | 15 | def initialize(rubygems_path = nil) 16 | if rubygems_path 17 | rubygems_cert_path = File.join(rubygems_path, "lib/rubygems/ssl_certs") 18 | @rubygems_certs = certificates_in(rubygems_cert_path) 19 | end 20 | 21 | @bundler_cert_path = File.expand_path("..", __FILE__) 22 | @bundler_certs = certificates_in(bundler_cert_path) 23 | end 24 | 25 | def up_to_date? 26 | rubygems_certs.all? do |rc| 27 | bundler_certs.find do |bc| 28 | File.basename(bc) == File.basename(rc) && FileUtils.compare_file(bc, rc) 29 | end 30 | end 31 | end 32 | 33 | def update! 34 | return if up_to_date? 35 | 36 | FileUtils.rm bundler_certs 37 | FileUtils.cp rubygems_certs, bundler_cert_path 38 | end 39 | 40 | def connect_to(host) 41 | http = Net::HTTP.new(host, 443) 42 | http.use_ssl = true 43 | http.verify_mode = OpenSSL::SSL::VERIFY_PEER 44 | http.cert_store = store 45 | http.head("/") 46 | end 47 | 48 | private 49 | 50 | def certificates_in(path) 51 | Dir[File.join(path, "**/*.pem")].sort 52 | end 53 | 54 | def store 55 | @store ||= begin 56 | store = OpenSSL::X509::Store.new 57 | bundler_certs.each do |cert| 58 | store.add_file cert 59 | end 60 | store 61 | end 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' 3 | module Bundler::Molinillo 4 | class DependencyGraph 5 | # @!visibility private 6 | # @see DependencyGraph#detach_vertex_named 7 | class DetachVertexNamed < Action 8 | # @!group Action 9 | 10 | # (see Action#name) 11 | def self.action_name 12 | :add_vertex 13 | end 14 | 15 | # (see Action#up) 16 | def up(graph) 17 | return [] unless @vertex = graph.vertices.delete(name) 18 | 19 | removed_vertices = [@vertex] 20 | @vertex.outgoing_edges.each do |e| 21 | v = e.destination 22 | v.incoming_edges.delete(e) 23 | if !v.root? && v.incoming_edges.empty? 24 | removed_vertices.concat graph.detach_vertex_named(v.name) 25 | end 26 | end 27 | 28 | @vertex.incoming_edges.each do |e| 29 | v = e.origin 30 | v.outgoing_edges.delete(e) 31 | end 32 | 33 | removed_vertices 34 | end 35 | 36 | # (see Action#down) 37 | def down(graph) 38 | return unless @vertex 39 | graph.vertices[@vertex.name] = @vertex 40 | @vertex.outgoing_edges.each do |e| 41 | e.destination.incoming_edges << e 42 | end 43 | @vertex.incoming_edges.each do |e| 44 | e.origin.outgoing_edges << e 45 | end 46 | end 47 | 48 | # @!group DetachVertexNamed 49 | 50 | # @return [String] the name of the vertex to detach 51 | attr_reader :name 52 | 53 | # Initialize an action to detach a vertex from a dependency graph 54 | # @param [String] name the name of the vertex to detach 55 | def initialize(name) 56 | @name = name 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler::Molinillo 3 | # A state that a {Resolution} can be in 4 | # @attr [String] name the name of the current requirement 5 | # @attr [Array] requirements currently unsatisfied requirements 6 | # @attr [DependencyGraph] activated the graph of activated dependencies 7 | # @attr [Object] requirement the current requirement 8 | # @attr [Object] possibilities the possibilities to satisfy the current requirement 9 | # @attr [Integer] depth the depth of the resolution 10 | # @attr [Set] conflicts unresolved conflicts 11 | ResolutionState = Struct.new( 12 | :name, 13 | :requirements, 14 | :activated, 15 | :requirement, 16 | :possibilities, 17 | :depth, 18 | :conflicts 19 | ) 20 | 21 | class ResolutionState 22 | # Returns an empty resolution state 23 | # @return [ResolutionState] an empty state 24 | def self.empty 25 | new(nil, [], DependencyGraph.new, nil, nil, 0, Set.new) 26 | end 27 | end 28 | 29 | # A state that encapsulates a set of {#requirements} with an {Array} of 30 | # possibilities 31 | class DependencyState < ResolutionState 32 | # Removes a possibility from `self` 33 | # @return [PossibilityState] a state with a single possibility, 34 | # the possibility that was removed from `self` 35 | def pop_possibility_state 36 | PossibilityState.new( 37 | name, 38 | requirements.dup, 39 | activated, 40 | requirement, 41 | [possibilities.pop], 42 | depth + 1, 43 | conflicts.dup 44 | ).tap do |state| 45 | state.activated.tag(state) 46 | end 47 | end 48 | end 49 | 50 | # A state that encapsulates a single possibility to fulfill the given 51 | # {#requirement} 52 | class PossibilityState < ResolutionState 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/bundler/retry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | # General purpose class for retrying code that may fail 4 | class Retry 5 | attr_accessor :name, :total_runs, :current_run 6 | 7 | class << self 8 | def default_attempts 9 | default_retries + 1 10 | end 11 | alias_method :attempts, :default_attempts 12 | 13 | def default_retries 14 | Bundler.settings[:retry] 15 | end 16 | end 17 | 18 | def initialize(name, exceptions = nil, retries = self.class.default_retries) 19 | @name = name 20 | @retries = retries 21 | @exceptions = Array(exceptions) || [] 22 | @total_runs = @retries + 1 # will run once, then upto attempts.times 23 | end 24 | 25 | def attempt(&block) 26 | @current_run = 0 27 | @failed = false 28 | @error = nil 29 | run(&block) while keep_trying? 30 | @result 31 | end 32 | alias_method :attempts, :attempt 33 | 34 | private 35 | 36 | def run(&block) 37 | @failed = false 38 | @current_run += 1 39 | @result = block.call 40 | rescue => e 41 | fail_attempt(e) 42 | end 43 | 44 | def fail_attempt(e) 45 | @failed = true 46 | if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } 47 | Bundler.ui.info "" unless Bundler.ui.debug? 48 | raise e 49 | end 50 | return true unless name 51 | Bundler.ui.info "" unless Bundler.ui.debug? # Add new line incase dots preceded this 52 | Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? 53 | end 54 | 55 | def keep_trying? 56 | return true if current_run.zero? 57 | return false if last_attempt? 58 | return true if @failed 59 | end 60 | 61 | def last_attempt? 62 | current_run >= total_runs 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/install/gemfile/eval_gemfile_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "spec_helper" 3 | 4 | RSpec.describe "bundle install with gemfile that uses eval_gemfile" do 5 | before do 6 | build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s| 7 | s.name = "gunks" 8 | s.version = "0.0.1" 9 | end 10 | end 11 | 12 | context "eval-ed Gemfile points to an internal gemspec" do 13 | before do 14 | create_file "Gemfile-other", <<-G 15 | gemspec :path => 'gems/gunks' 16 | G 17 | end 18 | 19 | it "installs the gemspec specified gem" do 20 | install_gemfile <<-G 21 | eval_gemfile 'Gemfile-other' 22 | G 23 | expect(out).to include("Resolving dependencies") 24 | expect(out).to include("Using gunks 0.0.1 from source at `gems/gunks`") 25 | expect(out).to include("Bundle complete") 26 | end 27 | end 28 | 29 | context "eval-ed Gemfile has relative-path gems" do 30 | before do 31 | build_lib("a", :path => "gems/a") 32 | create_file "nested/Gemfile-nested", <<-G 33 | gem "a", :path => "../gems/a" 34 | G 35 | 36 | gemfile <<-G 37 | eval_gemfile "nested/Gemfile-nested" 38 | G 39 | end 40 | 41 | it "installs the path gem" do 42 | bundle! :install 43 | expect(the_bundle).to include_gem("a 1.0") 44 | end 45 | end 46 | 47 | context "Gemfile uses gemspec paths after eval-ing a Gemfile" do 48 | before { create_file "other/Gemfile-other" } 49 | 50 | it "installs the gemspec specified gem" do 51 | install_gemfile <<-G 52 | eval_gemfile 'other/Gemfile-other' 53 | gemspec :path => 'gems/gunks' 54 | G 55 | expect(out).to include("Resolving dependencies") 56 | expect(out).to include("Using gunks 0.0.1 from source at `gems/gunks`") 57 | expect(out).to include("Bundle complete") 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/bundler/source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Source 4 | autoload :Gemspec, "bundler/source/gemspec" 5 | autoload :Git, "bundler/source/git" 6 | autoload :Path, "bundler/source/path" 7 | autoload :Rubygems, "bundler/source/rubygems" 8 | 9 | attr_accessor :dependency_names 10 | 11 | def unmet_deps 12 | specs.unmet_dependency_names 13 | end 14 | 15 | def version_message(spec) 16 | message = "#{spec.name} #{spec.version}" 17 | message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? 18 | 19 | if Bundler.locked_gems 20 | locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name } 21 | locked_spec_version = locked_spec.version if locked_spec 22 | if locked_spec_version && spec.version != locked_spec_version 23 | message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) 24 | end 25 | end 26 | 27 | message 28 | end 29 | 30 | def can_lock?(spec) 31 | spec.source == self 32 | end 33 | 34 | def include?(other) 35 | other == self 36 | end 37 | 38 | def inspect 39 | "#<#{self.class}:0x#{object_id} #{self}>" 40 | end 41 | 42 | private 43 | 44 | def version_color(spec_version, locked_spec_version) 45 | if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) 46 | # display yellow if there appears to be a regression 47 | earlier_version?(spec_version, locked_spec_version) ? :yellow : :green 48 | else 49 | # default to green if the versions cannot be directly compared 50 | :green 51 | end 52 | end 53 | 54 | def earlier_version?(spec_version, locked_spec_version) 55 | Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/bundler/source/rubygems/remote.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Source 4 | class Rubygems 5 | class Remote 6 | attr_reader :uri, :anonymized_uri, :original_uri 7 | 8 | def initialize(uri) 9 | orig_uri = uri 10 | uri = Bundler.settings.mirror_for(uri) 11 | @original_uri = orig_uri if orig_uri != uri 12 | fallback_auth = Bundler.settings.credentials_for(uri) 13 | 14 | @uri = apply_auth(uri, fallback_auth).freeze 15 | @anonymized_uri = remove_auth(@uri).freeze 16 | end 17 | 18 | # @return [String] A slug suitable for use as a cache key for this 19 | # remote. 20 | # 21 | def cache_slug 22 | @cache_slug ||= begin 23 | cache_uri = original_uri || uri 24 | 25 | uri_parts = [cache_uri.host, cache_uri.user, cache_uri.port, cache_uri.path] 26 | uri_digest = Digest::MD5.hexdigest(uri_parts.compact.join(".")) 27 | 28 | uri_parts[-1] = uri_digest 29 | uri_parts.compact.join(".") 30 | end 31 | end 32 | 33 | def to_s 34 | "rubygems remote at #{anonymized_uri}" 35 | end 36 | 37 | private 38 | 39 | def apply_auth(uri, auth) 40 | if auth && uri.userinfo.nil? 41 | uri = uri.dup 42 | uri.userinfo = auth 43 | end 44 | 45 | uri 46 | rescue URI::InvalidComponentError 47 | error_message = "Please CGI escape your usernames and passwords before " \ 48 | "setting them for authentication." 49 | raise HTTPError.new(error_message) 50 | end 51 | 52 | def remove_auth(uri) 53 | if uri.userinfo 54 | uri = uri.dup 55 | uri.user = uri.password = nil 56 | end 57 | 58 | uri 59 | end 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/bundler/plugin/dsl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Bundler 4 | module Plugin 5 | # Dsl to parse the Gemfile looking for plugins to install 6 | class DSL < Bundler::Dsl 7 | class PluginGemfileError < PluginError; end 8 | alias_method :_gem, :gem # To use for plugin installation as gem 9 | 10 | # So that we don't have to override all there methods to dummy ones 11 | # explicitly. 12 | # They will be handled by method_missing 13 | [:gemspec, :gem, :path, :install_if, :platforms, :env].each {|m| undef_method m } 14 | 15 | # This lists the plugins that was added automatically and not specified by 16 | # the user. 17 | # 18 | # When we encounter :type attribute with a source block, we add a plugin 19 | # by name bundler-source- to list of plugins to be installed. 20 | # 21 | # These plugins are optional and are not installed when there is conflict 22 | # with any other plugin. 23 | attr_reader :inferred_plugins 24 | 25 | def initialize 26 | super 27 | @sources = Plugin::SourceList.new 28 | @inferred_plugins = [] # The source plugins inferred from :type 29 | end 30 | 31 | def plugin(name, *args) 32 | _gem(name, *args) 33 | end 34 | 35 | def method_missing(name, *args) 36 | raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name 37 | end 38 | 39 | def source(source, *args, &blk) 40 | options = args.last.is_a?(Hash) ? args.pop.dup : {} 41 | options = normalize_hash(options) 42 | return super unless options.key?("type") 43 | 44 | plugin_name = "bundler-source-#{options["type"]}" 45 | 46 | return if @dependencies.any? {|d| d.name == plugin_name } 47 | 48 | plugin(plugin_name) 49 | @inferred_plugins << plugin_name 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/bundler/installer/standalone.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class Standalone 4 | def initialize(groups, definition) 5 | @specs = groups.empty? ? definition.requested_specs : definition.specs_for(groups.map(&:to_sym)) 6 | end 7 | 8 | def generate 9 | SharedHelpers.filesystem_access(bundler_path) do |p| 10 | FileUtils.mkdir_p(p) 11 | end 12 | File.open File.join(bundler_path, "setup.rb"), "w" do |file| 13 | file.puts "require 'rbconfig'" 14 | file.puts "# ruby 1.8.7 doesn't define RUBY_ENGINE" 15 | file.puts "ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'" 16 | file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" 17 | file.puts "path = File.expand_path('..', __FILE__)" 18 | paths.each do |path| 19 | file.puts %($:.unshift "\#{path}/#{path}") 20 | end 21 | end 22 | end 23 | 24 | private 25 | 26 | def paths 27 | @specs.map do |spec| 28 | next if spec.name == "bundler" 29 | Array(spec.require_paths).map do |path| 30 | gem_path(path, spec).sub(version_dir, '#{ruby_engine}/#{ruby_version}') 31 | # This is a static string intentionally. It's interpolated at a later time. 32 | end 33 | end.flatten 34 | end 35 | 36 | def version_dir 37 | "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}" 38 | end 39 | 40 | def bundler_path 41 | Bundler.root.join(Bundler.settings[:path], "bundler") 42 | end 43 | 44 | def gem_path(path, spec) 45 | full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) 46 | Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s 47 | rescue TypeError 48 | error_message = "#{spec.name} #{spec.version} has an invalid gemspec" 49 | raise Gem::InvalidSpecificationException.new(error_message) 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/bundler/cli/lock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/cli/common" 3 | 4 | module Bundler 5 | class CLI::Lock 6 | attr_reader :options 7 | 8 | def initialize(options) 9 | @options = options 10 | end 11 | 12 | def run 13 | unless Bundler.default_gemfile 14 | Bundler.ui.error "Unable to find a Gemfile to lock" 15 | exit 1 16 | end 17 | 18 | print = options[:print] 19 | ui = Bundler.ui 20 | Bundler.ui = UI::Silent.new if print 21 | 22 | Bundler::Fetcher.disable_endpoint = options["full-index"] 23 | 24 | update = options[:update] 25 | update = { :gems => update, :lock_shared_dependencies => options[:conservative] } if update.is_a?(Array) 26 | definition = Bundler.definition(update) 27 | 28 | Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] 29 | 30 | options["remove-platform"].each do |platform| 31 | definition.remove_platform(platform) 32 | end 33 | 34 | options["add-platform"].each do |platform_string| 35 | platform = Gem::Platform.new(platform_string) 36 | if platform.to_s == "unknown" 37 | Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ 38 | "and adding it will likely lead to resolution errors" 39 | end 40 | definition.add_platform(platform) 41 | end 42 | 43 | if definition.platforms.empty? 44 | raise InvalidOption, "Removing all platforms from the bundle is not allowed" 45 | end 46 | 47 | definition.resolve_remotely! unless options[:local] 48 | 49 | if print 50 | puts definition.to_lock 51 | else 52 | file = options[:lockfile] 53 | file = file ? File.expand_path(file) : Bundler.default_lockfile 54 | puts "Writing lockfile to #{file}" 55 | definition.lock(file) 56 | end 57 | 58 | Bundler.ui = ui 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' 3 | module Bundler::Molinillo 4 | class DependencyGraph 5 | # @!visibility private 6 | # (see DependencyGraph#add_vertex) 7 | class AddVertex < Action # :nodoc: 8 | # @!group Action 9 | 10 | # (see Action.action_name) 11 | def self.action_name 12 | :add_vertex 13 | end 14 | 15 | # (see Action#up) 16 | def up(graph) 17 | if existing = graph.vertices[name] 18 | @existing_payload = existing.payload 19 | @existing_root = existing.root 20 | end 21 | vertex = existing || Vertex.new(name, payload) 22 | graph.vertices[vertex.name] = vertex 23 | vertex.payload ||= payload 24 | vertex.root ||= root 25 | vertex 26 | end 27 | 28 | # (see Action#down) 29 | def down(graph) 30 | if defined?(@existing_payload) 31 | vertex = graph.vertices[name] 32 | vertex.payload = @existing_payload 33 | vertex.root = @existing_root 34 | else 35 | graph.vertices.delete(name) 36 | end 37 | end 38 | 39 | # @!group AddVertex 40 | 41 | # @return [String] the name of the vertex 42 | attr_reader :name 43 | 44 | # @return [Object] the payload for the vertex 45 | attr_reader :payload 46 | 47 | # @return [Boolean] whether the vertex is root or not 48 | attr_reader :root 49 | 50 | # Initialize an action to add a vertex to a dependency graph 51 | # @param [String] name the name of the vertex 52 | # @param [Object] payload the payload for the vertex 53 | # @param [Boolean] root whether the vertex is root or not 54 | def initialize(name, payload, root) 55 | @name = name 56 | @payload = payload 57 | @root = root 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler::Molinillo 3 | # Conveys information about the resolution process to a user. 4 | module UI 5 | # The {IO} object that should be used to print output. `STDOUT`, by default. 6 | # 7 | # @return [IO] 8 | def output 9 | STDOUT 10 | end 11 | 12 | # Called roughly every {#progress_rate}, this method should convey progress 13 | # to the user. 14 | # 15 | # @return [void] 16 | def indicate_progress 17 | output.print '.' unless debug? 18 | end 19 | 20 | # How often progress should be conveyed to the user via 21 | # {#indicate_progress}, in seconds. A third of a second, by default. 22 | # 23 | # @return [Float] 24 | def progress_rate 25 | 0.33 26 | end 27 | 28 | # Called before resolution begins. 29 | # 30 | # @return [void] 31 | def before_resolution 32 | output.print 'Resolving dependencies...' 33 | end 34 | 35 | # Called after resolution ends (either successfully or with an error). 36 | # By default, prints a newline. 37 | # 38 | # @return [void] 39 | def after_resolution 40 | output.puts 41 | end 42 | 43 | # Conveys debug information to the user. 44 | # 45 | # @param [Integer] depth the current depth of the resolution process. 46 | # @return [void] 47 | def debug(depth = 0) 48 | if debug? 49 | debug_info = yield 50 | debug_info = debug_info.inspect unless debug_info.is_a?(String) 51 | output.puts debug_info.split("\n").map { |s| ' ' * depth + s } 52 | end 53 | end 54 | 55 | # Whether or not debug messages should be printed. 56 | # By default, whether or not the `MOLINILLO_DEBUG` environment variable is 57 | # set. 58 | # 59 | # @return [Boolean] 60 | def debug? 61 | return @debug_mode if defined?(@debug_mode) 62 | @debug_mode = ENV['MOLINILLO_DEBUG'] 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /doc/development/PULL_REQUESTS.md: -------------------------------------------------------------------------------- 1 | # Submitting Pull Requests 2 | 3 | Before you submit a pull request, please remember to do the following: 4 | 5 | 1. Check your code format and style 6 | 2. Run the test suite 7 | 3. Use a meaningful commit message without tags 8 | 9 | ## Code formatting 10 | 11 | Make sure the code formatting and styling adheres to the guidelines. We use Rubocop for this. Lack of formatting adherence will result in automatic Travis build failures. 12 | 13 | $ bin/rubocop -a 14 | 15 | ## Tests 16 | 17 | Prior to submitting your PR, please run the test suite: 18 | 19 | $ bin/rspec 20 | 21 | If you are unable to run the entire test suite, please run the unit test suite and at least the integration specs related to the command or domain of Bundler that your code changes relate to. 22 | 23 | Ex. For a pull request that changes something with `bundle update`, you might run: 24 | 25 | $ bin/rspec spec/bundler 26 | $ bin/rspec spec/commands/update_spec.rb 27 | 28 | ## Commit messages 29 | 30 | Please ensure that the commit messages included in the pull request __do not__ have the following: 31 | - `@tag` Github user or team references (ex. `@indirect` or `@bundler/core`) 32 | - `#id` references to issues or pull requests (ex. `#43` or `bundler/bundler-site#12`) 33 | 34 | If you want to use these mechanisms, please instead include them in the pull request description. This prevents multiple notifications or references being created on commit rebases or pull request/branch force pushes. 35 | 36 | Additionally, do not use `[ci skip]` or `[skip ci]` mechanisms in your pull request titles/descriptions or commit messages. Every potential commit and pull request should run through Bundler's CI system. This applies to all changes/commits (ex. even a change to just documentation or the removal of a comment). 37 | 38 | ## CHANGELOG.md 39 | 40 | Don't forget to add your changes into the CHANGELOG! If you're submitting documentation, note the changes under the "Documentation" heading. 41 | -------------------------------------------------------------------------------- /lib/bundler/fetcher/index.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require "bundler/fetcher/base" 3 | require "rubygems/remote_fetcher" 4 | 5 | module Bundler 6 | class Fetcher 7 | class Index < Base 8 | def specs(_gem_names) 9 | Bundler.rubygems.fetch_all_remote_specs(remote) 10 | rescue Gem::RemoteFetcher::FetchError, OpenSSL::SSL::SSLError, Net::HTTPFatalError => e 11 | case e.message 12 | when /certificate verify failed/ 13 | raise CertificateFailureError.new(display_uri) 14 | when /401/ 15 | raise AuthenticationRequiredError, remote_uri 16 | when /403/ 17 | raise BadAuthenticationError, remote_uri if remote_uri.userinfo 18 | raise AuthenticationRequiredError, remote_uri 19 | else 20 | Bundler.ui.trace e 21 | raise HTTPError, "Could not fetch specs from #{display_uri}" 22 | end 23 | end 24 | 25 | def fetch_spec(spec) 26 | spec -= [nil, "ruby", ""] 27 | spec_file_name = "#{spec.join "-"}.gemspec" 28 | 29 | uri = URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") 30 | if uri.scheme == "file" 31 | Bundler.load_marshal Gem.inflate(Gem.read_binary(uri.path)) 32 | elsif cached_spec_path = gemspec_cached_path(spec_file_name) 33 | Bundler.load_gemspec(cached_spec_path) 34 | else 35 | Bundler.load_marshal Gem.inflate(downloader.fetch(uri).body) 36 | end 37 | rescue MarshalError 38 | raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ 39 | "Your network or your gem server is probably having issues right now." 40 | end 41 | 42 | private 43 | 44 | # cached gem specification path, if one exists 45 | def gemspec_cached_path(spec_file_name) 46 | paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } 47 | paths.find {|path| File.file? path } 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /doc/contributing/README.md: -------------------------------------------------------------------------------- 1 | # Contributing to Bundler 2 | 3 | Welcome to Bundler! We are so happy that you're here. We know it can be daunting to joining a new open source project, so here's a quick overview of what you can expect from this documentation. 4 | 5 | *Something missing?* Send us a [pull request](../development/PULL_REQUESTS.md)! 6 | 7 | **Recommended first steps** 8 | 9 | - Join us in the Bundler slack! Generate an invite [here](http://slack.bundler.io/) 10 | - *If you're interested in helping with code:* 11 | - Get a quick overview of our [development process](../development/README.md) 12 | - [Setup your machine for development](../development/SETUP.md) 13 | - Checkout [How you can help: your first contributions!](HOW_YOU_CAN_HELP.md) for a list of suggestions to get started 14 | - *If you're interested in helping with documentation:* 15 | - Read up on [how documentation works for Bundler](../documentation/README.md) 16 | - Learn about our [documentation vision](../documentation/VISION.md) 17 | 18 | You can start learning about Bundler by reading [the documentation](http://bundler.io). If you want, you can also read a (lengthy) explanation of [why Bundler exists and what it does](http://bundler.io/rationale.html). 19 | 20 | ##[How you can help: your first contributions!](HOW_YOU_CAN_HELP.md) 21 | 22 | A detailed overview of how to get started contributing to Bundler, including a long list of suggestions for your first project. 23 | 24 | ##[Bug triage](BUG_TRIAGE.md) 25 | 26 | Want to take a stab at processing issues? Start here. 27 | 28 | ##[Getting help](GETTING_HELP.md) 29 | 30 | How to get in touch with folks who can help when you're stuck. Don't worry! This happens to all of us. We're really nice, we promise. 31 | 32 | ##[Filing issues](ISSUES.md) 33 | 34 | We see a lot of issues in the Bundler repo! Use this guide to file informative, actionable issues. 35 | 36 | ##[Community](COMMUNITY.md) 37 | 38 | Learn more about our goals for the Bundler community and the ways you can help us build better together. 39 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/newgem.gemspec.tt: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path("../lib", __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require "<%= config[:namespaced_path] %>/version" 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = <%= config[:name].inspect %> 8 | spec.version = <%= config[:constant_name] %>::VERSION 9 | spec.authors = [<%= config[:author].inspect %>] 10 | spec.email = [<%= config[:email].inspect %>] 11 | 12 | spec.summary = %q{TODO: Write a short summary, because Rubygems requires one.} 13 | spec.description = %q{TODO: Write a longer description or delete this line.} 14 | spec.homepage = "TODO: Put your gem's website or public repo URL here." 15 | <%- if config[:mit] -%> 16 | spec.license = "MIT" 17 | <%- end -%> 18 | 19 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 20 | # to allow pushing to a single host or delete this section to allow pushing to any host. 21 | if spec.respond_to?(:metadata) 22 | spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" 23 | else 24 | raise "RubyGems 2.0 or newer is required to protect against " \ 25 | "public gem pushes." 26 | end 27 | 28 | spec.files = `git ls-files -z`.split("\x0").reject do |f| 29 | f.match(%r{^(test|spec|features)/}) 30 | end 31 | spec.bindir = "exe" 32 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 33 | spec.require_paths = ["lib"] 34 | <%- if config[:ext] -%> 35 | spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] 36 | <%- end -%> 37 | 38 | spec.add_development_dependency "bundler", "~> <%= config[:bundler_version] %>" 39 | spec.add_development_dependency "rake", "~> 10.0" 40 | <%- if config[:ext] -%> 41 | spec.add_development_dependency "rake-compiler" 42 | <%- end -%> 43 | <%- if config[:test] -%> 44 | spec.add_development_dependency "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" 45 | <%- end -%> 46 | end 47 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/actions/create_link.rb: -------------------------------------------------------------------------------- 1 | require "bundler/vendor/thor/lib/thor/actions/create_file" 2 | 3 | class Bundler::Thor 4 | module Actions 5 | # Create a new file relative to the destination root from the given source. 6 | # 7 | # ==== Parameters 8 | # destination:: the relative path to the destination root. 9 | # source:: the relative path to the source root. 10 | # config:: give :verbose => false to not log the status. 11 | # :: give :symbolic => false for hard link. 12 | # 13 | # ==== Examples 14 | # 15 | # create_link "config/apache.conf", "/etc/apache.conf" 16 | # 17 | def create_link(destination, *args) 18 | config = args.last.is_a?(Hash) ? args.pop : {} 19 | source = args.first 20 | action CreateLink.new(self, destination, source, config) 21 | end 22 | alias_method :add_link, :create_link 23 | 24 | # CreateLink is a subset of CreateFile, which instead of taking a block of 25 | # data, just takes a source string from the user. 26 | # 27 | class CreateLink < CreateFile #:nodoc: 28 | attr_reader :data 29 | 30 | # Checks if the content of the file at the destination is identical to the rendered result. 31 | # 32 | # ==== Returns 33 | # Boolean:: true if it is identical, false otherwise. 34 | # 35 | def identical? 36 | exists? && File.identical?(render, destination) 37 | end 38 | 39 | def invoke! 40 | invoke_with_conflict_check do 41 | FileUtils.mkdir_p(File.dirname(destination)) 42 | # Create a symlink by default 43 | config[:symbolic] = true if config[:symbolic].nil? 44 | File.unlink(destination) if exists? 45 | if config[:symbolic] 46 | File.symlink(render, destination) 47 | else 48 | File.link(render, destination) 49 | end 50 | end 51 | given_destination 52 | end 53 | 54 | def exists? 55 | super || File.symlink?(destination) 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/lib/thor/parser/argument.rb: -------------------------------------------------------------------------------- 1 | class Bundler::Thor 2 | class Argument #:nodoc: 3 | VALID_TYPES = [:numeric, :hash, :array, :string] 4 | 5 | attr_reader :name, :description, :enum, :required, :type, :default, :banner 6 | alias_method :human_name, :name 7 | 8 | def initialize(name, options = {}) 9 | class_name = self.class.name.split("::").last 10 | 11 | type = options[:type] 12 | 13 | raise ArgumentError, "#{class_name} name can't be nil." if name.nil? 14 | raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) 15 | 16 | @name = name.to_s 17 | @description = options[:desc] 18 | @required = options.key?(:required) ? options[:required] : true 19 | @type = (type || :string).to_sym 20 | @default = options[:default] 21 | @banner = options[:banner] || default_banner 22 | @enum = options[:enum] 23 | 24 | validate! # Trigger specific validations 25 | end 26 | 27 | def usage 28 | required? ? banner : "[#{banner}]" 29 | end 30 | 31 | def required? 32 | required 33 | end 34 | 35 | def show_default? 36 | case default 37 | when Array, String, Hash 38 | !default.empty? 39 | else 40 | default 41 | end 42 | end 43 | 44 | protected 45 | 46 | def validate! 47 | raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? 48 | raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array) 49 | end 50 | 51 | def valid_type?(type) 52 | self.class::VALID_TYPES.include?(type.to_sym) 53 | end 54 | 55 | def default_banner 56 | case type 57 | when :boolean 58 | nil 59 | when :string, :default 60 | human_name.upcase 61 | when :numeric 62 | "N" 63 | when :hash 64 | "key:value" 65 | when :array 66 | "one two three" 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/bundler/similarity_detector.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Bundler 3 | class SimilarityDetector 4 | SimilarityScore = Struct.new(:string, :distance) 5 | 6 | # initialize with an array of words to be matched against 7 | def initialize(corpus) 8 | @corpus = corpus 9 | end 10 | 11 | # return an array of words similar to 'word' from the corpus 12 | def similar_words(word, limit = 3) 13 | words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) } 14 | words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string) 15 | end 16 | 17 | # return the result of 'similar_words', concatenated into a list 18 | # (eg "a, b, or c") 19 | def similar_word_list(word, limit = 3) 20 | words = similar_words(word, limit) 21 | if words.length == 1 22 | words[0] 23 | elsif words.length > 1 24 | [words[0..-2].join(", "), words[-1]].join(" or ") 25 | end 26 | end 27 | 28 | protected 29 | 30 | # http://www.informit.com/articles/article.aspx?p=683059&seqNum=36 31 | def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1) 32 | # ins, del, sub are weighted costs 33 | return nil if this.nil? 34 | return nil if that.nil? 35 | dm = [] # distance matrix 36 | 37 | # Initialize first row values 38 | dm[0] = (0..this.length).collect {|i| i * ins } 39 | fill = [0] * (this.length - 1) 40 | 41 | # Initialize first column values 42 | (1..that.length).each do |i| 43 | dm[i] = [i * del, fill.flatten] 44 | end 45 | 46 | # populate matrix 47 | (1..that.length).each do |i| 48 | (1..this.length).each do |j| 49 | # critical comparison 50 | dm[i][j] = [ 51 | dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub), 52 | dm[i][j - 1] + ins, 53 | dm[i - 1][j] + del 54 | ].min 55 | end 56 | end 57 | 58 | # The last value in matrix is the Levenshtein distance between the strings 59 | dm[that.length][this.length] 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/support/sometimes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Sometimes 3 | def run_with_retries(example_to_run, retries) 4 | example = RSpec.current_example 5 | example.metadata[:retries] ||= retries 6 | 7 | retries.times do |t| 8 | example.metadata[:retried] = t + 1 9 | example.instance_variable_set(:@exception, nil) 10 | example_to_run.run 11 | break unless example.exception 12 | end 13 | 14 | if e = example.exception 15 | new_exception = e.exception(e.message + "[Retried #{retries} times]") 16 | new_exception.set_backtrace e.backtrace 17 | example.instance_variable_set(:@exception, new_exception) 18 | end 19 | end 20 | end 21 | 22 | RSpec.configure do |config| 23 | config.include Sometimes 24 | config.alias_example_to :sometimes, :sometimes => true 25 | config.add_setting :sometimes_retry_count, :default => 5 26 | 27 | config.around(:each, :sometimes => true) do |example| 28 | retries = example.metadata[:retries] || RSpec.configuration.sometimes_retry_count 29 | run_with_retries(example, retries) 30 | end 31 | 32 | config.after(:suite) do 33 | message = proc do |color, text| 34 | colored = RSpec::Core::Formatters::ConsoleCodes.wrap(text, color) 35 | notification = RSpec::Core::Notifications::MessageNotification.new(colored) 36 | formatter = RSpec.configuration.formatters.first 37 | formatter.message(notification) if formatter.respond_to?(:message) 38 | end 39 | 40 | retried_examples = RSpec.world.example_groups.map do |g| 41 | g.descendants.map do |d| 42 | d.filtered_examples.select do |e| 43 | e.metadata[:sometimes] && e.metadata.fetch(:retried, 1) > 1 44 | end 45 | end 46 | end.flatten 47 | 48 | message.call(retried_examples.empty? ? :green : :yellow, "\n\nRetried examples: #{retried_examples.count}") 49 | 50 | retried_examples.each do |e| 51 | message.call(:cyan, " #{e.full_description}") 52 | path = RSpec::Core::Metadata.relative_path(e.location) 53 | message.call(:cyan, " [#{e.metadata[:retried]}/#{e.metadata[:retries]}] " + path) 54 | end 55 | end 56 | end 57 | --------------------------------------------------------------------------------