├── lib └── bundler │ ├── templates │ ├── newgem │ │ ├── gitignore.tt │ │ ├── Rakefile.tt │ │ ├── bin │ │ │ └── newgem.tt │ │ ├── Gemfile.tt │ │ ├── lib │ │ │ ├── newgem.rb.tt │ │ │ └── newgem │ │ │ │ └── version.rb.tt │ │ └── newgem.gemspec.tt │ ├── Gemfile │ └── Executable │ ├── vendor │ └── thor │ │ ├── version.rb │ │ ├── parser.rb │ │ ├── core_ext │ │ ├── file_binary_read.rb │ │ ├── hash_with_indifferent_access.rb │ │ └── ordered_hash.rb │ │ ├── error.rb │ │ ├── parser │ │ ├── argument.rb │ │ ├── option.rb │ │ ├── arguments.rb │ │ └── options.rb │ │ ├── shell.rb │ │ ├── actions │ │ ├── directory.rb │ │ ├── inject_into_file.rb │ │ ├── create_file.rb │ │ └── empty_directory.rb │ │ ├── task.rb │ │ └── shell │ │ ├── color.rb │ │ └── html.rb │ ├── version.rb │ ├── vlad.rb │ ├── capistrano.rb │ ├── setup.rb │ ├── environment.rb │ ├── ui.rb │ ├── remote_specification.rb │ ├── lazy_specification.rb │ ├── deployment.rb │ ├── installer.rb │ ├── dependency.rb │ ├── settings.rb │ ├── lockfile_parser.rb │ ├── spec_set.rb │ ├── index.rb │ ├── graph.rb │ ├── gem_helper.rb │ ├── runtime.rb │ ├── shared_helpers.rb │ └── rubygems_ext.rb ├── man ├── index.txt ├── bundle.ronn ├── bundle-package.ronn ├── bundle-config.ronn └── bundle-exec.ronn ├── spec ├── support │ ├── rubygems_hax │ │ └── rubygems_plugin.rb │ ├── sudo.rb │ ├── ruby_ext.rb │ ├── platforms.rb │ ├── rubygems_ext.rb │ ├── path.rb │ ├── matchers.rb │ └── indexes.rb ├── cache │ ├── git_spec.rb │ ├── path_spec.rb │ └── platform_spec.rb ├── runtime │ ├── with_clean_env_spec.rb │ ├── platform_spec.rb │ ├── executable_spec.rb │ └── load_spec.rb ├── install │ ├── invalid_spec.rb │ ├── gems │ │ ├── win32_spec.rb │ │ ├── c_ext_spec.rb │ │ ├── packed_spec.rb │ │ ├── sudo_spec.rb │ │ ├── resolving_spec.rb │ │ ├── env_spec.rb │ │ └── platform_spec.rb │ ├── upgrade_spec.rb │ ├── deprecated_spec.rb │ └── gemspec_spec.rb ├── resolver │ ├── basic_spec.rb │ └── platform_spec.rb ├── pack │ └── gems_spec.rb ├── other │ ├── ext_spec.rb │ ├── newgem_spec.rb │ ├── init_spec.rb │ ├── help_spec.rb │ ├── config_spec.rb │ ├── console_spec.rb │ ├── open_spec.rb │ ├── show_spec.rb │ └── gem_helper_spec.rb ├── lock │ └── git_spec.rb ├── update │ ├── source_spec.rb │ └── gems_spec.rb ├── quality_spec.rb └── spec_helper.rb ├── .gitignore ├── bin └── bundle ├── LICENSE ├── bundler.gemspec ├── README.md ├── ISSUES.md ├── UPGRADING.md └── Rakefile /lib/bundler/templates/newgem/gitignore.tt: -------------------------------------------------------------------------------- 1 | pkg/* 2 | *.gem 3 | .bundle 4 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/version.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | VERSION = "0.14.0".freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/Rakefile.tt: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /lib/bundler/templates/Gemfile: -------------------------------------------------------------------------------- 1 | # A sample Gemfile 2 | source "http://rubygems.org" 3 | 4 | # gem "rails" 5 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/bin/newgem.tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "<%= config[:name] %>" 4 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/Gemfile.tt: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in <%=config[:name]%>.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/parser.rb: -------------------------------------------------------------------------------- 1 | require 'thor/parser/argument' 2 | require 'thor/parser/arguments' 3 | require 'thor/parser/option' 4 | require 'thor/parser/options' 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/core_ext/file_binary_read.rb: -------------------------------------------------------------------------------- 1 | class File #:nodoc: 2 | 3 | unless File.respond_to?(:binread) 4 | def self.binread(file) 5 | File.open(file, 'rb') { |f| f.read } 6 | end 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/bundler/version.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | # We're doing this because we might write tests that deal 3 | # with other versions of bundler and we are unsure how to 4 | # handle this better. 5 | VERSION = "1.0.7" unless defined?(::Bundler::VERSION) 6 | end 7 | -------------------------------------------------------------------------------- /spec/support/rubygems_hax/rubygems_plugin.rb: -------------------------------------------------------------------------------- 1 | class Gem::Platform 2 | @local = new(ENV['BUNDLER_SPEC_PLATFORM']) if ENV['BUNDLER_SPEC_PLATFORM'] 3 | end 4 | 5 | if ENV['BUNDLER_SPEC_VERSION'] 6 | module Bundler 7 | VERSION = ENV['BUNDLER_SPEC_VERSION'].dup 8 | end 9 | end -------------------------------------------------------------------------------- /spec/cache/git_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | describe "bundle cache with git" do 3 | it "base_name should strip private repo uris" do 4 | source = Bundler::Source::Git.new("uri" => "git@github.com:bundler.git") 5 | source.send(:base_name).should == "bundler" 6 | end 7 | end 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/lib/newgem.rb.tt: -------------------------------------------------------------------------------- 1 | <%- config[:constant_array].each_with_index do |c,i| -%> 2 | <%= ' '*i %>module <%= c %> 3 | <%- end -%> 4 | <%= ' '*config[:constant_array].size %># Your code goes here... 5 | <%- (config[:constant_array].size-1).downto(0) do |i| -%> 6 | <%= ' '*i %>end 7 | <%- end -%> 8 | -------------------------------------------------------------------------------- /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.0.1" 5 | <%- (config[:constant_array].size-1).downto(0) do |i| -%> 6 | <%= ' '*i %>end 7 | <%- end -%> 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # system crap 2 | .DS_Store 3 | .*.swp 4 | 5 | # files created by running the specs 6 | tmp 7 | 8 | # built gems 9 | pkg 10 | *.gem 11 | 12 | # rubinius bytecode 13 | *.rbc 14 | 15 | # output from ronn 16 | lib/bundler/man 17 | 18 | # output from ci_reporter 19 | spec/reports 20 | 21 | # Netbeans 22 | nbproject 23 | -------------------------------------------------------------------------------- /lib/bundler/vlad.rb: -------------------------------------------------------------------------------- 1 | # Vlad task for Bundler. 2 | # 3 | # Just add "require 'bundler/vlad'" in your Vlad deploy.rb, and 4 | # include the vlad:bundle:install task in your vlad:deploy task. 5 | require 'bundler/deployment' 6 | 7 | namespace :vlad do 8 | Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app) 9 | end -------------------------------------------------------------------------------- /spec/runtime/with_clean_env_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Bundler.with_clean_env" do 4 | 5 | it "should reset and restore the environment" do 6 | gem_path = ENV['GEM_PATH'] 7 | 8 | Bundler.with_clean_env do 9 | `echo $GEM_PATH`.strip.should_not == gem_path 10 | end 11 | 12 | ENV['GEM_PATH'].should == gem_path 13 | end 14 | 15 | end -------------------------------------------------------------------------------- /spec/install/invalid_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install with deprecated features" do 4 | before :each do 5 | in_app_root 6 | end 7 | 8 | it "reports that lib is an invalid option" do 9 | gemfile <<-G 10 | gem "rack", :lib => "rack" 11 | G 12 | 13 | bundle :install 14 | out.should =~ /You passed :lib as an option for gem 'rack', but it is invalid/ 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /lib/bundler/capistrano.rb: -------------------------------------------------------------------------------- 1 | # Capistrano task for Bundler. 2 | # 3 | # Just add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and 4 | # Bundler will be activated after each new deployment. 5 | require 'bundler/deployment' 6 | 7 | Capistrano::Configuration.instance(:must_exist).load do 8 | after "deploy:update_code", "bundle:install" 9 | Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) 10 | end 11 | -------------------------------------------------------------------------------- /spec/resolver/basic_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Resolving" do 4 | 5 | before :each do 6 | @index = an_awesome_index 7 | end 8 | 9 | it "resolves a single gem" do 10 | dep "rack" 11 | 12 | should_resolve_as %w(rack-1.1) 13 | end 14 | 15 | it "resolves a gem with dependencies" do 16 | dep "actionpack" 17 | 18 | should_resolve_as %w(actionpack-2.3.5 activesupport-2.3.5 rack-1.0) 19 | end 20 | end -------------------------------------------------------------------------------- /spec/support/sudo.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Sudo 3 | def self.present? 4 | @which_sudo ||= (`which sudo`.chomp rescue '') 5 | !@which_sudo.empty? 6 | end 7 | 8 | def self.test_sudo? 9 | present? && ENV['BUNDLER_SUDO_TESTS'] 10 | end 11 | 12 | def sudo(cmd) 13 | raise "sudo not present" unless Sudo.present? 14 | sys_exec("sudo #{cmd}") 15 | end 16 | 17 | def chown_system_gems_to_root 18 | sudo "chown -R root #{system_gem_path}" 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/pack/gems_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle pack with gems" do 4 | describe "when there are only gemsources" do 5 | before :each do 6 | gemfile <<-G 7 | gem 'rack' 8 | G 9 | 10 | system_gems "rack-1.0.0" 11 | bundle :pack 12 | end 13 | 14 | it "locks the gemfile" do 15 | bundled_app("Gemfile.lock").should exist 16 | end 17 | 18 | it "caches the gems" do 19 | bundled_app("vendor/cache/rack-1.0.0.gem").should exist 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /lib/bundler/setup.rb: -------------------------------------------------------------------------------- 1 | require 'bundler/shared_helpers' 2 | 3 | if Bundler::SharedHelpers.in_bundle? 4 | require 'bundler' 5 | begin 6 | Bundler.setup 7 | rescue Bundler::BundlerError => e 8 | puts "\e[31m#{e.message}\e[0m" 9 | puts e.backtrace.join("\n") if ENV["DEBUG"] 10 | exit e.status_code 11 | end 12 | 13 | # Add bundler to the load path after disabling system gems 14 | bundler_lib = File.expand_path("../..", __FILE__) 15 | $LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib) 16 | end 17 | -------------------------------------------------------------------------------- /spec/other/ext_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Gem::Specification#match_platform" do 4 | it "does not match platforms other than the gem platform" do 5 | darwin = gem "lol", "1.0", "platform_specific-1.0-x86-darwin-10" 6 | darwin.match_platform(pl('java')).should be_false 7 | end 8 | end 9 | 10 | describe "Bundler::GemHelpers#generic" do 11 | include Bundler::GemHelpers 12 | 13 | it "converts non-windows platforms into ruby" do 14 | generic(pl('x86-darwin-10')).should == pl('ruby') 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/bundler/templates/Executable: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env <%= 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 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../<%= relative_gemfile_path %>", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('<%= spec.name %>', '<%= executable %>') 17 | -------------------------------------------------------------------------------- /spec/support/ruby_ext.rb: -------------------------------------------------------------------------------- 1 | class IO 2 | def read_available_bytes(chunk_size = 16384, select_timeout = 0.02) 3 | buffer = [] 4 | 5 | return "" if closed? || eof? 6 | # IO.select cannot be used here due to the fact that it 7 | # just does not work on windows 8 | while true 9 | begin 10 | IO.select([self], nil, nil, select_timeout) 11 | break if eof? # stop raising :-( 12 | buffer << self.readpartial(chunk_size) 13 | rescue(EOFError) 14 | break 15 | end 16 | end 17 | 18 | return buffer.join 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Check if an older version of bundler is installed 4 | require 'bundler' 5 | $:.each do |path| 6 | if path =~ %r'/bundler-0.(\d+)' && $1.to_i < 9 7 | abort "Please remove older versions of bundler. This can be done by running `gem cleanup bundler`." 8 | end 9 | end 10 | require 'bundler/cli' 11 | 12 | begin 13 | Bundler::CLI.start 14 | rescue Bundler::BundlerError => e 15 | Bundler.ui.error e.message 16 | Bundler.ui.debug e.backtrace.join("\n") 17 | exit e.status_code 18 | rescue Interrupt => e 19 | Bundler.ui.error "\nQuitting..." 20 | Bundler.ui.debug e.backtrace.join("\n") 21 | exit 1 22 | end 23 | -------------------------------------------------------------------------------- /spec/install/gems/win32_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "bundle install with win32-generated lockfile" do 4 | it 'should read lockfile' do 5 | File.open(bundled_app('Gemfile.lock'), 'wb') do |f| 6 | f << "GEM\r\n" 7 | f << " remote: file:#{gem_repo1}/\r\n" 8 | f << " specs:\r\n" 9 | f << "\r\n" 10 | f << " rack (1.0.0)\r\n" 11 | f << "\r\n" 12 | f << "PLATFORMS\r\n" 13 | f << " ruby\r\n" 14 | f << "\r\n" 15 | f << "DEPENDENCIES\r\n" 16 | f << " rack\r\n" 17 | end 18 | 19 | install_gemfile <<-G, :exitstatus => true 20 | source "file://#{gem_repo1}" 21 | 22 | gem "rack" 23 | G 24 | @exitstatus.should == 0 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/install/upgrade_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install for the first time with v1.0" do 4 | before :each do 5 | in_app_root 6 | 7 | gemfile <<-G 8 | source "file://#{gem_repo1}" 9 | gem "rack" 10 | G 11 | end 12 | 13 | it "removes lockfiles in 0.9 YAML format" do 14 | File.open("Gemfile.lock", "w"){|f| YAML.dump({}, f) } 15 | bundle :install 16 | File.read("Gemfile.lock").should_not =~ /^---/ 17 | end 18 | 19 | it "removes env.rb if it exists" do 20 | bundled_app.join(".bundle").mkdir 21 | bundled_app.join(".bundle/environment.rb").open("w"){|f| f.write("raise 'nooo'") } 22 | bundle :install 23 | bundled_app.join(".bundle/environment.rb").should_not exist 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/cache/path_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle cache" do 4 | describe "with path sources" do 5 | it "is silent when the path is within the bundle" do 6 | build_lib "foo", :path => bundled_app("lib/foo") 7 | 8 | install_gemfile <<-G 9 | gem "foo", :path => '#{bundled_app("lib/foo")}' 10 | G 11 | 12 | bundle "cache" 13 | out.should == "Updating .gem files in vendor/cache" 14 | end 15 | 16 | it "warns when the path is outside of the bundle" do 17 | build_lib "foo" 18 | 19 | install_gemfile <<-G 20 | gem "foo", :path => '#{lib_path("foo-1.0")}' 21 | G 22 | 23 | bundle "cache" 24 | out.should include("foo at `#{lib_path("foo-1.0")}` will not be cached") 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/lock/git_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle lock with git gems" do 4 | before :each do 5 | build_git "foo" 6 | 7 | install_gemfile <<-G 8 | gem 'foo', :git => "#{lib_path('foo-1.0')}" 9 | G 10 | end 11 | 12 | it "doesn't break right after running lock" do 13 | should_be_installed "foo 1.0.0" 14 | end 15 | 16 | it "locks a git source to the current ref" do 17 | update_git "foo" 18 | bundle :install 19 | 20 | run <<-RUBY 21 | require 'foo' 22 | puts "WIN" unless defined?(FOO_PREV_REF) 23 | RUBY 24 | 25 | out.should == "WIN" 26 | end 27 | 28 | it "provides correct #full_gem_path" do 29 | run <<-RUBY 30 | puts Gem.source_index.find_name('foo').first.full_gem_path 31 | RUBY 32 | out.should == bundle("show foo") 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /spec/other/newgem_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle gem" do 4 | before :each do 5 | bundle 'gem test-gem' 6 | end 7 | 8 | it "generates a gem skeleton" do 9 | bundled_app("test-gem/test-gem.gemspec").should exist 10 | bundled_app("test-gem/Gemfile").should exist 11 | bundled_app("test-gem/Rakefile").should exist 12 | bundled_app("test-gem/lib/test-gem.rb").should exist 13 | bundled_app("test-gem/lib/test-gem/version.rb").should exist 14 | end 15 | 16 | it "starts with version 0.0.1" do 17 | bundled_app("test-gem/lib/test-gem/version.rb").read.should =~ /VERSION = "0.0.1"/ 18 | end 19 | 20 | it "nests constants so they work" do 21 | bundled_app("test-gem/lib/test-gem/version.rb").read.should =~ /module Test\n module Gem/ 22 | bundled_app("test-gem/lib/test-gem.rb").read.should =~ /module Test\n module Gem/ 23 | end 24 | end -------------------------------------------------------------------------------- /lib/bundler/templates/newgem/newgem.gemspec.tt: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "<%=config[:name]%>/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = <%=config[:name].inspect%> 7 | s.version = <%=config[:constant_name]%>::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["TODO: Write your name"] 10 | s.email = ["TODO: Write your email address"] 11 | s.homepage = "" 12 | s.summary = %q{TODO: Write a gem summary} 13 | s.description = %q{TODO: Write a gem description} 14 | 15 | s.rubyforge_project = <%=config[:name].inspect%> 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 20 | s.require_paths = ["lib"] 21 | end 22 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/error.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | # Thor::Error is raised when it's caused by wrong usage of thor classes. Those 3 | # errors have their backtrace supressed 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, it SHOULD NOT raise a Thor::Error. This way, we 7 | # ensure that developer errors are shown with full backtrace. 8 | # 9 | class Error < StandardError 10 | end 11 | 12 | # Raised when a task was not found. 13 | # 14 | class UndefinedTaskError < Error 15 | end 16 | 17 | # Raised when a task was found, but not invoked properly. 18 | # 19 | class InvocationError < Error 20 | end 21 | 22 | class UnknownArgumentError < Error 23 | end 24 | 25 | class RequiredArgumentMissingError < InvocationError 26 | end 27 | 28 | class MalformattedArgumentError < InvocationError 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/bundler/environment.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class Environment 3 | attr_reader :root 4 | 5 | def initialize(root, definition) 6 | @root = root 7 | @definition = definition 8 | 9 | env_file = Bundler.app_config_path.join('environment.rb') 10 | env_file.rmtree if env_file.exist? 11 | end 12 | 13 | def inspect 14 | @definition.to_lock.inspect 15 | end 16 | 17 | # TODO: Remove this method. It's used in cli.rb still 18 | def index 19 | @definition.index 20 | end 21 | 22 | def requested_specs 23 | @definition.requested_specs 24 | end 25 | 26 | def specs 27 | @definition.specs 28 | end 29 | 30 | def dependencies 31 | @definition.dependencies 32 | end 33 | 34 | def current_dependencies 35 | @definition.current_dependencies 36 | end 37 | 38 | def lock 39 | @definition.lock(Bundler.default_lockfile) 40 | end 41 | 42 | def update(*gems) 43 | # Nothing 44 | end 45 | 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/support/platforms.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Platforms 3 | include Bundler::GemHelpers 4 | 5 | def rb 6 | Gem::Platform::RUBY 7 | end 8 | 9 | def mac 10 | Gem::Platform.new('x86-darwin-10') 11 | end 12 | 13 | def java 14 | Gem::Platform.new([nil, "java", nil]) 15 | end 16 | 17 | def linux 18 | Gem::Platform.new(['x86', 'linux', nil]) 19 | end 20 | 21 | def mswin 22 | Gem::Platform.new(['x86', 'mswin32', nil]) 23 | end 24 | 25 | def mingw 26 | Gem::Platform.new(['x86', 'mingw32', nil]) 27 | end 28 | 29 | def all_platforms 30 | [rb, java, linux, mswin, mingw] 31 | end 32 | 33 | def local 34 | generic(Gem::Platform.local) 35 | end 36 | 37 | def not_local 38 | all_platforms.find { |p| p != generic(Gem::Platform.local) } 39 | end 40 | 41 | def local_tag 42 | if RUBY_PLATFORM == "java" 43 | :jruby 44 | else 45 | :ruby 46 | end 47 | end 48 | 49 | def not_local_tag 50 | [:ruby, :jruby].find { |tag| tag != local_tag } 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Portions copyright (c) 2010 Andre Arko 2 | Portions copyright (c) 2009 Engine Yard 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /spec/other/init_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle init" do 4 | it "generates a Gemfile" do 5 | bundle :init 6 | bundled_app("Gemfile").should exist 7 | end 8 | 9 | it "does not change existing Gemfiles" do 10 | gemfile <<-G 11 | gem "rails" 12 | G 13 | 14 | lambda { 15 | bundle :init 16 | }.should_not change { File.read(bundled_app("Gemfile")) } 17 | end 18 | 19 | it "should generate from an existing gemspec" do 20 | spec_file = tmp.join('test.gemspec') 21 | File.open(spec_file, 'w') do |file| 22 | file << <<-S 23 | Gem::Specification.new do |s| 24 | s.name = 'test' 25 | s.add_dependency 'rack', '= 1.0.1' 26 | s.add_development_dependency 'rspec', '1.2' 27 | end 28 | S 29 | end 30 | 31 | bundle :init, :gemspec => spec_file 32 | 33 | gemfile = bundled_app("Gemfile").read 34 | gemfile.should =~ /source :gemcutter/ 35 | check gemfile.scan(/gem "rack", "= 1.0.1"/).size.should == 1 36 | check gemfile.scan(/gem "rspec", "= 1.2"/).size.should == 1 37 | check gemfile.scan(/group :development/).size.should == 1 38 | end 39 | 40 | end -------------------------------------------------------------------------------- /spec/install/deprecated_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install with deprecated features" do 4 | before :each do 5 | in_app_root 6 | end 7 | 8 | %w( only except disable_system_gems disable_rubygems 9 | clear_sources bundle_path bin_path ).each do |deprecated| 10 | 11 | it "reports that #{deprecated} is deprecated" do 12 | gemfile <<-G 13 | #{deprecated} 14 | G 15 | 16 | bundle :install 17 | out.should =~ /'#{deprecated}' has been removed/ 18 | out.should =~ /See the README for more information/ 19 | end 20 | 21 | end 22 | 23 | 24 | %w( require_as vendored_at only except ).each do |deprecated| 25 | 26 | it "reports that :#{deprecated} is deprecated" do 27 | gemfile <<-G 28 | gem "rack", :#{deprecated} => true 29 | G 30 | 31 | bundle :install 32 | out.should =~ /Please replace :#{deprecated}|The :#{deprecated} option is no longer supported/ 33 | end 34 | 35 | end 36 | 37 | it "reports that --production is deprecated" do 38 | gemfile %{gem "rack"} 39 | bundle "install --production" 40 | out.should =~ /--production option is deprecated/ 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /spec/other/help_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle help" do 4 | it "complains if older versions of bundler are installed" do 5 | system_gems "bundler-0.8.1" 6 | 7 | bundle "help", :expect_err => true 8 | err.should == "Please remove older versions of bundler. This can be done by running `gem cleanup bundler`." 9 | end 10 | 11 | it "uses groff when available" do 12 | fake_groff! 13 | 14 | bundle "help gemfile" 15 | out.should == %|["-Wall", "-mtty-char", "-mandoc", "-Tascii", "#{root}/lib/bundler/man/gemfile.5"]| 16 | end 17 | 18 | it "prefixes bundle commands with bundle- when finding the groff files" do 19 | fake_groff! 20 | 21 | bundle "help install" 22 | out.should == %|["-Wall", "-mtty-char", "-mandoc", "-Tascii", "#{root}/lib/bundler/man/bundle-install"]| 23 | end 24 | 25 | it "simply outputs the txt file when there is no groff on the path" do 26 | kill_path! 27 | 28 | bundle "help install", :expect_err => true 29 | out.should =~ /BUNDLE-INSTALL/ 30 | end 31 | 32 | it "still outputs the old help for commands that do not have man pages yet" do 33 | bundle "help check" 34 | out.should include("Check searches the local machine") 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /bundler.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | lib = File.expand_path('../lib/', __FILE__) 3 | $:.unshift lib unless $:.include?(lib) 4 | 5 | require 'bundler/version' 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "bundler" 9 | s.version = Bundler::VERSION 10 | s.platform = Gem::Platform::RUBY 11 | s.authors = ["Carl Lerche", "Yehuda Katz", "André Arko"] 12 | s.email = ["carlhuda@engineyard.com"] 13 | s.homepage = "http://gembundler.com" 14 | s.summary = %q{The best way to manage your application's dependencies} 15 | s.description = %q{Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably} 16 | 17 | s.required_rubygems_version = ">= 1.3.6" 18 | s.rubyforge_project = "bundler" 19 | 20 | s.add_development_dependency "ronn" 21 | s.add_development_dependency "rspec" 22 | 23 | # Man files are required because they are ignored by git 24 | man_files = Dir.glob("lib/bundler/man/**/*") 25 | s.files = `git ls-files`.split("\n") + man_files 26 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 27 | s.executables = %w(bundle) 28 | s.default_executable = "bundle" 29 | s.require_paths = ["lib"] 30 | end 31 | -------------------------------------------------------------------------------- /spec/other/config_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe ".bundle/config" do 4 | before :each do 5 | gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rack", "1.0.0" 8 | G 9 | end 10 | 11 | it "can be moved with an environment variable" do 12 | ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s 13 | bundle "install --path vendor/bundle" 14 | 15 | bundled_app('.bundle').should_not exist 16 | tmp('foo/bar/config').should exist 17 | should_be_installed "rack 1.0.0" 18 | end 19 | 20 | it "can provide a relative path with the environment variable" do 21 | FileUtils.mkdir_p bundled_app('omg') 22 | Dir.chdir bundled_app('omg') 23 | 24 | ENV['BUNDLE_APP_CONFIG'] = "../foo" 25 | bundle "install --path vendor/bundle" 26 | 27 | bundled_app(".bundle").should_not exist 28 | bundled_app("../foo/config").should exist 29 | should_be_installed "rack 1.0.0" 30 | end 31 | 32 | it "removes environment.rb from BUNDLE_APP_CONFIG's path" do 33 | FileUtils.mkdir_p(tmp('foo/bar')) 34 | ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s 35 | bundle "install" 36 | FileUtils.touch tmp('foo/bar/environment.rb') 37 | should_be_installed "rack 1.0.0" 38 | tmp('foo/bar/environment.rb').should_not exist 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/support/rubygems_ext.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Rubygems 3 | def self.setup 4 | Gem.clear_paths 5 | 6 | ENV['BUNDLE_PATH'] = nil 7 | ENV['GEM_HOME'] = ENV['GEM_PATH'] = Path.base_system_gems.to_s 8 | ENV['PATH'] = ["#{Path.root}/bin", "#{Path.system_gem_path}/bin", ENV['PATH']].join(File::PATH_SEPARATOR) 9 | 10 | unless File.exist?("#{Path.base_system_gems}") 11 | FileUtils.mkdir_p(Path.base_system_gems) 12 | puts "running `gem install rake fakeweb --no-rdoc --no-ri`" 13 | `gem install rake fakeweb --no-rdoc --no-ri` 14 | # 3.0.0 breaks 1.9.2 specs 15 | puts "running `gem install builder --version 2.1.2 --no-rdoc --no-ri`" 16 | `gem install builder --version 2.1.2 --no-rdoc --no-ri` 17 | end 18 | 19 | ENV['HOME'] = Path.home.to_s 20 | 21 | Gem::DefaultUserInteraction.ui = Gem::SilentUI.new 22 | end 23 | 24 | def gem_command(command, args = "", options = {}) 25 | if command == :exec && !options[:no_quote] 26 | args = args.gsub(/(?=")/, "\\") 27 | args = %["#{args}"] 28 | end 29 | lib = File.join(File.dirname(__FILE__), '..', '..', 'lib') 30 | %x{#{Gem.ruby} -I#{lib} -rubygems -S gem --backtrace #{command} #{args}}.strip 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/update/source_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle update" do 4 | describe "git sources" do 5 | before :each do 6 | build_repo2 7 | @git = build_git "foo", :path => lib_path("foo") do |s| 8 | s.executables = "foobar" 9 | end 10 | 11 | install_gemfile <<-G 12 | source "file://#{gem_repo2}" 13 | git "#{lib_path('foo')}" do 14 | gem 'foo' 15 | end 16 | gem 'rack' 17 | G 18 | end 19 | 20 | it "updates the source" do 21 | update_git "foo", :path => @git.path 22 | 23 | bundle "update --source foo" 24 | 25 | in_app_root do 26 | run <<-RUBY 27 | require 'foo' 28 | puts "WIN" if defined?(FOO_PREV_REF) 29 | RUBY 30 | 31 | out.should == "WIN" 32 | end 33 | end 34 | 35 | it "unlocks gems that were originally pulled in by the source" do 36 | update_git "foo", "2.0", :path => @git.path 37 | 38 | bundle "update --source foo" 39 | should_be_installed "foo 2.0" 40 | end 41 | 42 | it "leaves all other gems frozen" do 43 | update_repo2 44 | update_git "foo", :path => @git.path 45 | 46 | bundle "update --source foo" 47 | should_be_installed "rack 1.0" 48 | end 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /lib/bundler/ui.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class UI 3 | def warn(message) 4 | end 5 | 6 | def debug(message) 7 | end 8 | 9 | def error(message) 10 | end 11 | 12 | def info(message) 13 | end 14 | 15 | def confirm(message) 16 | end 17 | 18 | class Shell < UI 19 | attr_writer :shell 20 | 21 | def initialize(shell) 22 | @shell = shell 23 | @quiet = false 24 | @debug = ENV['DEBUG'] 25 | end 26 | 27 | def debug(msg) 28 | @shell.say(msg) if @debug && !@quiet 29 | end 30 | 31 | def info(msg) 32 | @shell.say(msg) if !@quiet 33 | end 34 | 35 | def confirm(msg) 36 | @shell.say(msg, :green) if !@quiet 37 | end 38 | 39 | def warn(msg) 40 | @shell.say(msg, :yellow) 41 | end 42 | 43 | def error(msg) 44 | @shell.say(msg, :red) 45 | end 46 | 47 | def be_quiet! 48 | @quiet = true 49 | end 50 | 51 | def debug! 52 | @debug = true 53 | end 54 | end 55 | 56 | class RGProxy < Gem::SilentUI 57 | def initialize(ui) 58 | @ui = ui 59 | end 60 | 61 | def say(message) 62 | if message =~ /native extensions/ 63 | @ui.info "with native extensions " 64 | else 65 | @ui.debug(message) 66 | end 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/install/gems/c_ext_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "installing a gem with C extensions" do 4 | it "installs" do 5 | build_repo2 do 6 | build_gem "c_extension" do |s| 7 | s.extensions = ["ext/extconf.rb"] 8 | s.write "ext/extconf.rb", <<-E 9 | require "mkmf" 10 | name = "c_extension_bundle" 11 | dir_config(name) 12 | raise "OMG" unless with_config("c_extension") == "hello" 13 | create_makefile(name) 14 | E 15 | 16 | s.write "ext/c_extension.c", <<-C 17 | #include "ruby.h" 18 | 19 | VALUE c_extension_true(VALUE self) { 20 | return Qtrue; 21 | } 22 | 23 | void Init_c_extension_bundle() { 24 | VALUE c_Extension = rb_define_class("CExtension", rb_cObject); 25 | rb_define_method(c_Extension, "its_true", c_extension_true, 0); 26 | } 27 | C 28 | 29 | s.write "lib/c_extension.rb", <<-C 30 | require "c_extension_bundle" 31 | C 32 | end 33 | end 34 | 35 | gemfile <<-G 36 | source "file://#{gem_repo2}" 37 | gem "c_extension" 38 | G 39 | 40 | bundle "config build.c_extension --with-c_extension=hello" 41 | bundle "install" 42 | 43 | out.should_not include("extconf.rb failed") 44 | 45 | run "Bundler.require; puts CExtension.new.its_true" 46 | out.should == "true" 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bundler: a gem to bundle gems 2 | 3 | Bundler is a tool that manages gem dependencies for your ruby application. It 4 | takes a gem manifest file and is able to fetch, download, and install the gems 5 | and all child dependencies specified in this manifest. It can manage any update 6 | to the gem manifest file and update the bundle's gems accordingly. It also lets 7 | you run any ruby code in context of the bundle's gem environment. 8 | 9 | ### Installation and usage 10 | 11 | See [gembundler.com](http://gembundler.com) for up-to-date installation and usage instructions. 12 | 13 | ### Troubleshooting 14 | 15 | For help with common problems, see [ISSUES](http://github.com/carlhuda/bundler/blob/master/ISSUES.md). 16 | 17 | ### Development 18 | 19 | To see what has changed in recent versions of bundler, see the [CHANGELOG](http://github.com/carlhuda/bundler/blob/master/CHANGELOG.md). 20 | 21 | The `master` branch contains our current progress towards version 1.1. Because of that, please submit bugfix pull requests against the `1-0-stable` branch. 22 | 23 | ### Upgrading from Bundler 0.8 to 0.9 and above 24 | 25 | See [UPGRADING](http://github.com/carlhuda/bundler/blob/master/UPGRADING.md). 26 | 27 | ### Other questions 28 | 29 | Feel free to chat with the Bundler core team (and many other users) on IRC in the [#bundler](irc://irc.freenode.net/bundler) channel on Freenode, or via email on the [Bundler mailing list](http://groups.google.com/group/ruby-bundler). 30 | -------------------------------------------------------------------------------- /spec/other/console_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle console" do 4 | before :each do 5 | install_gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rack" 8 | gem "activesupport", :group => :test 9 | gem "rack_middleware", :group => :development 10 | G 11 | end 12 | 13 | it "starts IRB with the default group loaded" do 14 | bundle "console" do |input| 15 | input.puts("puts RACK") 16 | input.puts("exit") 17 | end 18 | out.should include("0.9.1") 19 | end 20 | 21 | it "doesn't load any other groups" do 22 | bundle "console" do |input| 23 | input.puts("puts ACTIVESUPPORT") 24 | input.puts("exit") 25 | end 26 | out.should include("NameError") 27 | end 28 | 29 | describe "when given a group" do 30 | it "loads the given group" do 31 | bundle "console test" do |input| 32 | input.puts("puts ACTIVESUPPORT") 33 | input.puts("exit") 34 | end 35 | out.should include("2.3.5") 36 | end 37 | 38 | it "loads the default group" do 39 | bundle "console test" do |input| 40 | input.puts("puts RACK") 41 | input.puts("exit") 42 | end 43 | out.should include("0.9.1") 44 | end 45 | 46 | it "doesn't load other groups" do 47 | bundle "console test" do |input| 48 | input.puts("puts RACK_MIDDLEWARE") 49 | input.puts("exit") 50 | end 51 | out.should include("NameError") 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/other/open_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle open" do 4 | before :each do 5 | install_gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rails" 8 | G 9 | end 10 | 11 | it "opens the gem with BUNDLER_EDITOR as highest priority" do 12 | bundle "open rails", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor"} 13 | out.should == "bundler_editor #{default_bundle_path('gems', 'rails-2.3.2')}" 14 | end 15 | 16 | it "opens the gem with VISUAL as 2nd highest priority" do 17 | bundle "open rails", :env => {"EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => ""} 18 | out.should == "visual #{default_bundle_path('gems', 'rails-2.3.2')}" 19 | end 20 | 21 | it "opens the gem with EDITOR as 3rd highest priority" do 22 | bundle "open rails", :env => {"EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => ""} 23 | out.should == "editor #{default_bundle_path('gems', 'rails-2.3.2')}" 24 | end 25 | 26 | it "complains if no EDITOR is set" do 27 | bundle "open rails", :env => {"EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => ""} 28 | out.should == "To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR" 29 | end 30 | 31 | it "complains if gem not in bundle" do 32 | bundle "open missing", :env => {"EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => ""} 33 | out.should match(/could not find gem 'missing'/i) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/support/path.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Path 3 | def root 4 | @root ||= Pathname.new(File.expand_path("../../..", __FILE__)) 5 | end 6 | 7 | def tmp(*path) 8 | root.join("tmp", *path) 9 | end 10 | 11 | def home(*path) 12 | tmp.join("home", *path) 13 | end 14 | 15 | def default_bundle_path(*path) 16 | system_gem_path(*path) 17 | end 18 | 19 | def bundled_app(*path) 20 | root = tmp.join("bundled_app") 21 | FileUtils.mkdir_p(root) 22 | root.join(*path) 23 | end 24 | 25 | alias bundled_app1 bundled_app 26 | 27 | def bundled_app2(*path) 28 | root = tmp.join("bundled_app2") 29 | FileUtils.mkdir_p(root) 30 | root.join(*path) 31 | end 32 | 33 | def vendored_gems(path = nil) 34 | bundled_app("vendor/bundle/#{Gem.ruby_engine}/#{Gem::ConfigMap[:ruby_version]}/#{path}") 35 | end 36 | 37 | def cached_gem(path) 38 | bundled_app("vendor/cache/#{path}.gem") 39 | end 40 | 41 | def base_system_gems 42 | tmp.join("gems/base") 43 | end 44 | 45 | def gem_repo1(*args) 46 | tmp("gems/remote1", *args) 47 | end 48 | 49 | def gem_repo2(*args) 50 | tmp("gems/remote2", *args) 51 | end 52 | 53 | def gem_repo3(*args) 54 | tmp("gems/remote3", *args) 55 | end 56 | 57 | def system_gem_path(*path) 58 | tmp("gems/system", *path) 59 | end 60 | 61 | def lib_path(*args) 62 | tmp("libs", *args) 63 | end 64 | 65 | def bundler_path 66 | Pathname.new(File.expand_path('../../../lib', __FILE__)) 67 | end 68 | 69 | extend self 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/cache/platform_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle cache with multiple platforms" do 4 | before :each do 5 | gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | 8 | platforms :ruby, :ruby_18, :ruby_19 do 9 | gem "rack", "1.0.0" 10 | end 11 | 12 | platforms :jruby do 13 | gem "activesupport", "2.3.5" 14 | end 15 | 16 | platforms :mri, :mri_18, :mri_19 do 17 | gem "activerecord", "2.3.2" 18 | end 19 | G 20 | 21 | lockfile <<-G 22 | GEM 23 | remote: file:#{gem_repo1}/ 24 | specs: 25 | rack (1.0.0) 26 | activesupport (2.3.5) 27 | activerecord (2.3.2) 28 | 29 | PLATFORMS 30 | ruby 31 | java 32 | 33 | DEPENDENCIES 34 | rack (1.0.0) 35 | activesupport (2.3.5) 36 | activerecord (2.3.2) 37 | G 38 | 39 | cache_gems "rack-1.0.0", "activesupport-2.3.5", "activerecord-2.3.2" 40 | end 41 | 42 | it "ensures that bundle install does not delete gems for other platforms" do 43 | bundle "install" 44 | 45 | bundled_app("vendor/cache/rack-1.0.0.gem").should exist 46 | bundled_app("vendor/cache/activesupport-2.3.5.gem").should exist 47 | bundled_app("vendor/cache/activerecord-2.3.2.gem").should exist 48 | end 49 | 50 | it "ensures that bundle update does not delete gems for other platforms" do 51 | bundle "update" 52 | 53 | bundled_app("vendor/cache/rack-1.0.0.gem").should exist 54 | bundled_app("vendor/cache/activesupport-2.3.5.gem").should exist 55 | bundled_app("vendor/cache/activerecord-2.3.2.gem").should exist 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/quality_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "The library itself" do 4 | def check_for_tab_characters(filename) 5 | failing_lines = [] 6 | File.readlines(filename).each_with_index do |line,number| 7 | failing_lines << number + 1 if line =~ /\t/ 8 | end 9 | 10 | unless failing_lines.empty? 11 | "#{filename} has tab characters on lines #{failing_lines.join(', ')}" 12 | end 13 | end 14 | 15 | def check_for_extra_spaces(filename) 16 | failing_lines = [] 17 | File.readlines(filename).each_with_index do |line,number| 18 | next if line =~ /^\s+#.*\s+\n$/ 19 | failing_lines << number + 1 if line =~ /\s+\n$/ 20 | end 21 | 22 | unless failing_lines.empty? 23 | "#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}" 24 | end 25 | end 26 | 27 | RSpec::Matchers.define :be_well_formed do 28 | failure_message_for_should do |actual| 29 | actual.join("\n") 30 | end 31 | 32 | match do |actual| 33 | actual.empty? 34 | end 35 | end 36 | 37 | it "has no malformed whitespace" do 38 | error_messages = [] 39 | Dir.chdir(File.expand_path("../..", __FILE__)) do 40 | `git ls-files`.split("\n").each do |filename| 41 | next if filename =~ /\.gitmodules|fixtures/ 42 | error_messages << check_for_tab_characters(filename) 43 | error_messages << check_for_extra_spaces(filename) 44 | end 45 | end 46 | error_messages.compact.should be_well_formed 47 | end 48 | 49 | it "can still be built" do 50 | Dir.chdir(root) do 51 | `gem build bundler.gemspec` 52 | $?.should == 0 53 | 54 | # clean up the .gem generated 55 | system("rm bundler-#{Bundler::VERSION}.gem") 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /ISSUES.md: -------------------------------------------------------------------------------- 1 | # Bundler Issues 2 | 3 | ## Troubleshooting 4 | 5 | Instructions for common Bundler use-cases can be found on the [Bundler documentation site](http://gembundler.com/v1.0/). Detailed information about each Bundler command, including help with common problems, can be found in the [Bundler man pages](http://gembundler.com/man/bundle.1.html). 6 | 7 | After reading the documentation, try these troubleshooting steps: 8 | 9 | # remove user-specific gems and git repos 10 | rm -rf ~/.bundle/ ~/.gem/ 11 | 12 | # remove system-wide git repos and git checkouts 13 | rm -rf $GEM_HOME/bundler/ $GEM_HOME/cache/bundler/ 14 | 15 | # remove project-specific settings and git repos 16 | rm -rf .bundle/ 17 | 18 | # remove project-specific cached .gem files 19 | rm -rf vendor/cache/ 20 | 21 | # remove the saved resolve of the Gemfile 22 | rm -rf Gemfile.lock 23 | 24 | # try to install one more time 25 | bundle install 26 | 27 | ## Reporting unresolved problems 28 | 29 | If you are still having problems, please report issues to the [Bundler issue tracker](http://github.com/carlhuda/bundler/issues/). 30 | 31 | Instructions that allow the Bundler team to reproduce your issue are vitally important. When you report a bug, please create a gist of the following information and include a link in your ticket: 32 | 33 | - What version of bundler you are using 34 | - What version of Ruby you are using 35 | - Whether you are using RVM, and if so what version 36 | - Your Gemfile 37 | - Your Gemfile.lock 38 | - If you are on 0.9, whether you have locked or not 39 | - If you are on 1.0, the result of `bundle config` 40 | - The command you ran to generate exception(s) 41 | - The exception backtrace(s) 42 | 43 | If you are using Rails 2.3, please also include: 44 | 45 | - Your boot.rb file 46 | - Your preinitializer.rb file 47 | - Your environment.rb file 48 | -------------------------------------------------------------------------------- /lib/bundler/remote_specification.rb: -------------------------------------------------------------------------------- 1 | require "uri" 2 | require "rubygems/spec_fetcher" 3 | 4 | module Bundler 5 | # Represents a lazily loaded gem specification, where the full specification 6 | # is on the source server in rubygems' "quick" index. The proxy object is to 7 | # be seeded with what we're given from the source's abbreviated index - the 8 | # full specification will only be fetched when necesary. 9 | class RemoteSpecification 10 | include MatchPlatform 11 | 12 | attr_reader :name, :version, :platform 13 | attr_accessor :source 14 | 15 | def initialize(name, version, platform, source_uri) 16 | @name = name 17 | @version = version 18 | @platform = platform 19 | @source_uri = source_uri 20 | end 21 | 22 | # Needed before installs, since the arch matters then and quick 23 | # specs don't bother to include the arch in the platform string 24 | def fetch_platform 25 | @platform = _remote_specification.platform 26 | end 27 | 28 | def full_name 29 | if platform == Gem::Platform::RUBY or platform.nil? then 30 | "#{@name}-#{@version}" 31 | else 32 | "#{@name}-#{@version}-#{platform}" 33 | end 34 | end 35 | 36 | # Because Rubyforge cannot be trusted to provide valid specifications 37 | # once the remote gem is downloaded, the backend specification will 38 | # be swapped out. 39 | def __swap__(spec) 40 | @specification = spec 41 | end 42 | 43 | private 44 | 45 | def _remote_specification 46 | @specification ||= begin 47 | Gem::SpecFetcher.new.fetch_spec([@name, @version, @platform], URI(@source_uri.to_s)) 48 | end 49 | end 50 | 51 | def method_missing(method, *args, &blk) 52 | if Gem::Specification.new.respond_to?(method) 53 | _remote_specification.send(method, *args, &blk) 54 | else 55 | super 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/parser/argument.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | class Argument #:nodoc: 3 | VALID_TYPES = [ :numeric, :hash, :array, :string ] 4 | 5 | attr_reader :name, :description, :required, :type, :default, :banner 6 | alias :human_name :name 7 | 8 | def initialize(name, description=nil, required=true, type=:string, default=nil, banner=nil) 9 | class_name = self.class.name.split("::").last 10 | 11 | raise ArgumentError, "#{class_name} name can't be nil." if name.nil? 12 | raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) 13 | 14 | @name = name.to_s 15 | @description = description 16 | @required = required || false 17 | @type = (type || :string).to_sym 18 | @default = default 19 | @banner = banner || default_banner 20 | 21 | validate! # Trigger specific validations 22 | end 23 | 24 | def usage 25 | required? ? banner : "[#{banner}]" 26 | end 27 | 28 | def required? 29 | required 30 | end 31 | 32 | def show_default? 33 | case default 34 | when Array, String, Hash 35 | !default.empty? 36 | else 37 | default 38 | end 39 | end 40 | 41 | protected 42 | 43 | def validate! 44 | raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? 45 | end 46 | 47 | def valid_type?(type) 48 | self.class::VALID_TYPES.include?(type.to_sym) 49 | end 50 | 51 | def default_banner 52 | case type 53 | when :boolean 54 | nil 55 | when :string, :default 56 | human_name.upcase 57 | when :numeric 58 | "N" 59 | when :hash 60 | "key:value" 61 | when :array 62 | "one two three" 63 | end 64 | end 65 | 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/install/gems/packed_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install with gem sources" do 4 | describe "when cached and locked" do 5 | it "does not hit the remote at all" do 6 | build_repo2 7 | install_gemfile <<-G 8 | source "file://#{gem_repo2}" 9 | gem "rack" 10 | G 11 | 12 | bundle :pack 13 | simulate_new_machine 14 | FileUtils.rm_rf gem_repo2 15 | 16 | bundle "install --local" 17 | should_be_installed "rack 1.0.0" 18 | end 19 | 20 | it "does not hit the remote at all" do 21 | build_repo2 22 | install_gemfile <<-G 23 | source "file://#{gem_repo2}" 24 | gem "rack" 25 | G 26 | 27 | bundle :pack 28 | simulate_new_machine 29 | FileUtils.rm_rf gem_repo2 30 | 31 | bundle "install --deployment" 32 | should_be_installed "rack 1.0.0" 33 | end 34 | 35 | it "does not reinstall already-installed gems" do 36 | install_gemfile <<-G 37 | source "file://#{gem_repo1}" 38 | gem "rack" 39 | G 40 | bundle :pack 41 | 42 | build_gem "rack", "1.0.0", :path => bundled_app('vendor/cache') do |s| 43 | s.write "lib/rack.rb", "raise 'omg'" 44 | end 45 | 46 | bundle :install 47 | err.should be_empty 48 | should_be_installed "rack 1.0" 49 | end 50 | 51 | it "ignores cached gems for the wrong platform" do 52 | simulate_platform "java" do 53 | install_gemfile <<-G 54 | source "file://#{gem_repo1}" 55 | gem "platform_specific" 56 | G 57 | bundle :pack 58 | end 59 | 60 | simulate_new_machine 61 | 62 | simulate_platform "ruby" do 63 | install_gemfile <<-G 64 | source "file://#{gem_repo1}" 65 | gem "platform_specific" 66 | G 67 | run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" 68 | out.should == "1.0.0 RUBY" 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/bundler/lazy_specification.rb: -------------------------------------------------------------------------------- 1 | require "uri" 2 | require "rubygems/spec_fetcher" 3 | 4 | module Bundler 5 | class LazySpecification 6 | include MatchPlatform 7 | 8 | attr_reader :name, :version, :dependencies, :platform 9 | attr_accessor :source 10 | 11 | def initialize(name, version, platform, source = nil) 12 | @name = name 13 | @version = version 14 | @dependencies = [] 15 | @platform = platform 16 | @source = source 17 | @specification = nil 18 | end 19 | 20 | def full_name 21 | if platform == Gem::Platform::RUBY or platform.nil? then 22 | "#{@name}-#{@version}" 23 | else 24 | "#{@name}-#{@version}-#{platform}" 25 | end 26 | end 27 | 28 | def satisfies?(dependency) 29 | @name == dependency.name && dependency.requirement.satisfied_by?(Gem::Version.new(@version)) 30 | end 31 | 32 | def to_lock 33 | if platform == Gem::Platform::RUBY or platform.nil? 34 | out = " #{name} (#{version})\n" 35 | else 36 | out = " #{name} (#{version}-#{platform})\n" 37 | end 38 | 39 | dependencies.sort_by {|d| d.name }.each do |dep| 40 | next if dep.type == :development 41 | out << " #{dep.to_lock}\n" 42 | end 43 | 44 | out 45 | end 46 | 47 | def __materialize__ 48 | @specification = source.specs.search(Gem::Dependency.new(name, version)).last 49 | end 50 | 51 | def respond_to?(*args) 52 | super || @specification.respond_to?(*args) 53 | end 54 | 55 | def to_s 56 | "#{name} (#{version})" 57 | end 58 | 59 | private 60 | 61 | def method_missing(method, *args, &blk) 62 | if Gem::Specification.new.respond_to?(method) 63 | raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification 64 | @specification.send(method, *args, &blk) 65 | else 66 | super 67 | end 68 | end 69 | 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | module CoreExt #:nodoc: 3 | 4 | # A hash with indifferent access and magic predicates. 5 | # 6 | # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true 7 | # 8 | # hash[:foo] #=> 'bar' 9 | # hash['foo'] #=> 'bar' 10 | # hash.foo? #=> true 11 | # 12 | class HashWithIndifferentAccess < ::Hash #:nodoc: 13 | 14 | def initialize(hash={}) 15 | super() 16 | hash.each do |key, value| 17 | self[convert_key(key)] = value 18 | end 19 | end 20 | 21 | def [](key) 22 | super(convert_key(key)) 23 | end 24 | 25 | def []=(key, value) 26 | super(convert_key(key), value) 27 | end 28 | 29 | def delete(key) 30 | super(convert_key(key)) 31 | end 32 | 33 | def values_at(*indices) 34 | indices.collect { |key| self[convert_key(key)] } 35 | end 36 | 37 | def merge(other) 38 | dup.merge!(other) 39 | end 40 | 41 | def merge!(other) 42 | other.each do |key, value| 43 | self[convert_key(key)] = value 44 | end 45 | self 46 | end 47 | 48 | protected 49 | 50 | def convert_key(key) 51 | key.is_a?(Symbol) ? key.to_s : key 52 | end 53 | 54 | # Magic predicates. For instance: 55 | # 56 | # options.force? # => !!options['force'] 57 | # options.shebang # => "/usr/lib/local/ruby" 58 | # options.test_framework?(:rspec) # => options[:test_framework] == :rspec 59 | # 60 | def method_missing(method, *args, &block) 61 | method = method.to_s 62 | if method =~ /^(\w+)\?$/ 63 | if args.empty? 64 | !!self[$1] 65 | else 66 | self[$1] == args.first 67 | end 68 | else 69 | self[method] 70 | end 71 | end 72 | 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/runtime/platform_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Bundler.setup with multi platform stuff" do 4 | it "raises a friendly error when gems are missing locally" do 5 | gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rack" 8 | G 9 | 10 | lockfile <<-G 11 | GEM 12 | remote: file:#{gem_repo1}/ 13 | specs: 14 | rack (1.0) 15 | 16 | PLATFORMS 17 | #{local_tag} 18 | 19 | DEPENDENCIES 20 | rack 21 | G 22 | 23 | ruby <<-R 24 | begin 25 | require 'bundler' 26 | Bundler.setup 27 | rescue Bundler::GemNotFound => e 28 | puts "WIN" 29 | end 30 | R 31 | 32 | out.should == "WIN" 33 | end 34 | 35 | it "will resolve correctly on the current platform when the lockfile was targetted for a different one" do 36 | lockfile <<-G 37 | GEM 38 | remote: file:#{gem_repo1}/ 39 | specs: 40 | nokogiri (1.4.2-java) 41 | weakling (= 0.0.3) 42 | weakling (0.0.3) 43 | 44 | PLATFORMS 45 | java 46 | 47 | DEPENDENCIES 48 | nokogiri 49 | G 50 | 51 | system_gems "nokogiri-1.4.2" 52 | 53 | simulate_platform "x86-darwin-10" 54 | gemfile <<-G 55 | source "file://#{gem_repo1}" 56 | gem "nokogiri" 57 | G 58 | 59 | should_be_installed "nokogiri 1.4.2" 60 | end 61 | 62 | it "will add the resolve for the current platform" do 63 | lockfile <<-G 64 | GEM 65 | remote: file:#{gem_repo1}/ 66 | specs: 67 | nokogiri (1.4.2-java) 68 | weakling (= 0.0.3) 69 | weakling (0.0.3) 70 | 71 | PLATFORMS 72 | java 73 | 74 | DEPENDENCIES 75 | nokogiri 76 | G 77 | 78 | system_gems "nokogiri-1.4.2", "platform_specific-1.0-x86-darwin-100" 79 | 80 | simulate_platform "x86-darwin-100" 81 | 82 | gemfile <<-G 83 | source "file://#{gem_repo1}" 84 | gem "nokogiri" 85 | gem "platform_specific" 86 | G 87 | 88 | should_be_installed "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100" 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /spec/install/gems/sudo_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "when using sudo", :sudo => true do 4 | describe "and GEM_HOME is owned by root" do 5 | before :each do 6 | chown_system_gems_to_root 7 | end 8 | 9 | it "installs" do 10 | install_gemfile <<-G 11 | source "file://#{gem_repo1}" 12 | gem "rack", '1.0' 13 | G 14 | 15 | system_gem_path("gems/rack-1.0.0").should exist 16 | check system_gem_path("gems/rack-1.0.0").stat.uid.should == 0 17 | should_be_installed "rack 1.0" 18 | end 19 | 20 | it "installs when BUNDLE_PATH is owned by root" do 21 | bundle_path = tmp("owned_by_root") 22 | FileUtils.mkdir_p bundle_path 23 | sudo "chown -R root #{bundle_path}" 24 | 25 | ENV['BUNDLE_PATH'] = bundle_path.to_s 26 | install_gemfile <<-G 27 | source "file://#{gem_repo1}" 28 | gem "rack", '1.0' 29 | G 30 | 31 | bundle_path.join("gems/rack-1.0.0").should exist 32 | check bundle_path.join("gems/rack-1.0.0").stat.uid.should == 0 33 | should_be_installed "rack 1.0" 34 | end 35 | 36 | it "installs when BUNDLE_PATH does not exist" 37 | end 38 | 39 | describe "and BUNDLE_PATH is not writable" do 40 | it "installs" do 41 | sudo "chmod ugo-w #{default_bundle_path}" 42 | install_gemfile <<-G 43 | source "file://#{gem_repo1}" 44 | gem "rack", '1.0' 45 | G 46 | 47 | default_bundle_path("gems/rack-1.0.0").should exist 48 | should_be_installed "rack 1.0" 49 | end 50 | end 51 | 52 | describe "and BUNDLE_PATH is not writable" do 53 | it "installs" do 54 | begin 55 | gem_home = tmp('sudo_gem_home') 56 | 57 | sudo "mkdir -p #{gem_home}" 58 | sudo "chmod ugo-w #{gem_home}" 59 | ENV['GEM_HOME'] = gem_home.to_s 60 | ENV['GEM_PATH'] = nil 61 | 62 | install_gemfile <<-G 63 | source "file://#{gem_repo1}" 64 | gem "rack", '1.0' 65 | G 66 | 67 | gem_home.join('bin/rackup').should exist 68 | should_be_installed "rack 1.0" 69 | end 70 | end 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /spec/resolver/platform_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Resolving platform craziness" do 4 | describe "with cross-platform gems" do 5 | before :each do 6 | @index = an_awesome_index 7 | end 8 | 9 | it "resolves a simple multi platform gem" do 10 | dep "nokogiri" 11 | platforms "ruby", "java" 12 | 13 | should_resolve_as %w(nokogiri-1.4.2 nokogiri-1.4.2-java weakling-0.0.3) 14 | end 15 | 16 | it "doesn't pull gems that don't exist for the current platform" do 17 | dep "nokogiri" 18 | platforms "ruby" 19 | 20 | should_resolve_as %w(nokogiri-1.4.2) 21 | end 22 | 23 | it "doesn't pull gems when the version is available for all requested platforms" do 24 | dep "nokogiri" 25 | platforms "mswin32" 26 | 27 | should_resolve_as %w(nokogiri-1.4.2.1-x86-mswin32) 28 | end 29 | end 30 | 31 | describe "with mingw32" do 32 | 33 | before :each do 34 | @index = build_index do 35 | platforms "mingw32 mswin32" do |platform| 36 | gem "thin", "1.2.7", platform 37 | end 38 | end 39 | end 40 | 41 | it "finds mswin gems" do 42 | # win32 is hardcoded to get CPU x86 in rubygems 43 | platforms "mswin32" 44 | dep "thin" 45 | should_resolve_as %w(thin-1.2.7-x86-mswin32) 46 | end 47 | 48 | it "finds mingw gems" do 49 | # mingw is _not_ hardcoded to add CPU x86 in rubygems 50 | platforms "x86-mingw32" 51 | dep "thin" 52 | should_resolve_as %w(thin-1.2.7-x86-mingw32) 53 | end 54 | end 55 | 56 | describe "with conflicting cases" do 57 | before :each do 58 | @index = build_index do 59 | gem "foo", "1.0.0" do 60 | dep "bar", ">= 0" 61 | end 62 | 63 | gem 'bar', "1.0.0" do 64 | dep "baz", "~> 1.0.0" 65 | end 66 | 67 | gem "bar", "1.0.0", "java" do 68 | dep "baz", " ~> 1.1.0" 69 | end 70 | 71 | gem "baz", %w(1.0.0 1.1.0 1.2.0) 72 | end 73 | end 74 | 75 | it "reports on the conflict" do 76 | platforms "ruby", "java" 77 | dep "foo" 78 | 79 | should_conflict_on "baz" 80 | end 81 | end 82 | end -------------------------------------------------------------------------------- /spec/install/gems/resolving_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install with gem sources" do 4 | describe "install time dependencies" do 5 | it "installs gems with implicit rake dependencies" do 6 | install_gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | gem "with_implicit_rake_dep" 9 | gem "another_implicit_rake_dep" 10 | gem "rake" 11 | G 12 | 13 | run <<-R 14 | require 'implicit_rake_dep' 15 | require 'another_implicit_rake_dep' 16 | puts IMPLICIT_RAKE_DEP 17 | puts ANOTHER_IMPLICIT_RAKE_DEP 18 | R 19 | out.should == "YES\nYES" 20 | end 21 | 22 | it "installs gems with a dependency with no type" do 23 | build_repo2 24 | 25 | path = "#{gem_repo2}/#{Gem::MARSHAL_SPEC_DIR}/actionpack-2.3.2.gemspec.rz" 26 | spec = Marshal.load(Gem.inflate(File.read(path))) 27 | spec.dependencies.each do |d| 28 | d.instance_variable_set(:@type, :fail) 29 | end 30 | File.open(path, 'w') do |f| 31 | f.write Gem.deflate(Marshal.dump(spec)) 32 | end 33 | 34 | install_gemfile <<-G 35 | source "file://#{gem_repo2}" 36 | gem "actionpack", "2.3.2" 37 | G 38 | 39 | should_be_installed "actionpack 2.3.2", "activesupport 2.3.2" 40 | end 41 | 42 | describe "with crazy rubygem plugin stuff" do 43 | it "installs plugins" do 44 | install_gemfile <<-G 45 | source "file://#{gem_repo1}" 46 | gem "net_b" 47 | G 48 | 49 | should_be_installed "net_b 1.0" 50 | end 51 | 52 | it "installs plugins depended on by other plugins" do 53 | install_gemfile <<-G 54 | source "file://#{gem_repo1}" 55 | gem "net_a" 56 | G 57 | 58 | should_be_installed "net_a 1.0", "net_b 1.0" 59 | end 60 | 61 | it "installs multiple levels of dependencies" do 62 | install_gemfile <<-G 63 | source "file://#{gem_repo1}" 64 | gem "net_c" 65 | gem "net_e" 66 | G 67 | 68 | should_be_installed "net_a 1.0", "net_b 1.0", "net_c 1.0", "net_d 1.0", "net_e 1.0" 69 | end 70 | end 71 | end 72 | end -------------------------------------------------------------------------------- /man/bundle.ronn: -------------------------------------------------------------------------------- 1 | bundle(1) -- Ruby Dependency Management 2 | ======================================= 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle` COMMAND [--no-color] [--verbose] [ARGS] 7 | 8 | ## DESCRIPTION 9 | 10 | Bundler manages an `application's dependencies` through its entire life 11 | across many machines systematically and repeatably. 12 | 13 | See [the bundler website](http://gembundler.com) for information on getting 14 | started, and Gemfile(5) for more information on the `Gemfile` format. 15 | 16 | ## OPTIONS 17 | 18 | * `--no-color`: 19 | Prints all output without color 20 | 21 | * `--verbose`: 22 | Prints out additional logging information 23 | 24 | ## BUNDLE COMMANDS 25 | 26 | We divide `bundle` subcommands into primary commands and utilities. 27 | 28 | ## PRIMARY COMMANDS 29 | 30 | * [bundle install(1)][bundle-install]: 31 | Install the gems specified by the `Gemfile` or `Gemfile.lock` 32 | 33 | * [bundle update(1)][bundle-update]: 34 | Update dependencies to their latest versions 35 | 36 | * [bundle package(1)][bundle-package]: 37 | Package the .gem files required by your application into the 38 | `vendor/cache` directory 39 | 40 | * [bundle exec(1)][bundle-exec]: 41 | Execute a script in the context of the current bundle 42 | 43 | * [bundle config(1)][bundle-config]: 44 | Specify and read configuration options for bundler 45 | 46 | ## UTILITIES 47 | 48 | * `bundle check(1)`: 49 | Determine whether the requirements for your application are installed 50 | and available to bundler 51 | 52 | * `bundle list(1)`: 53 | Show all of the gems in the current bundle 54 | 55 | * `bundle show(1)`: 56 | Show the source location of a particular gem in the bundle 57 | 58 | * `bundle console(1)`: 59 | Start an IRB session in the context of the current bundle 60 | 61 | * `bundle open(1)`: 62 | Open an installed gem in the editor 63 | 64 | * `bundle viz(1)`: 65 | Generate a visual representation of your dependencies 66 | 67 | * `bundle init(1)`: 68 | Generate a simple `Gemfile`, placed in the current directory 69 | 70 | * `bundle gem(1)`: 71 | Create a simple gem, suitable for development with bundler 72 | 73 | ## OBSOLETE 74 | 75 | These commands are obsolete and should no longer be used 76 | 77 | * `bundle lock(1)` 78 | * `bundle unlock(1)` 79 | * `bundle cache(1)` 80 | 81 | -------------------------------------------------------------------------------- /spec/other/show_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle show" do 4 | before :each do 5 | install_gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rails" 8 | G 9 | end 10 | 11 | it "creates a Gemfile.lock if one did not exist" do 12 | FileUtils.rm("Gemfile.lock") 13 | 14 | bundle "show" 15 | 16 | bundled_app("Gemfile.lock").should exist 17 | end 18 | 19 | it "creates a Gemfile.lock if one did not exist and we're doing bundle show rails" do 20 | FileUtils.rm("Gemfile.lock") 21 | 22 | bundle "show rails" 23 | 24 | bundled_app("Gemfile.lock").should exist 25 | end 26 | 27 | it "prints path if gem exists in bundle" do 28 | bundle "show rails" 29 | out.should == default_bundle_path('gems', 'rails-2.3.2').to_s 30 | end 31 | 32 | it "prints the path to the running bundler" do 33 | bundle "show bundler" 34 | out.should == File.expand_path('../../../', __FILE__) 35 | end 36 | 37 | it "complains if gem not in bundle" do 38 | bundle "show missing" 39 | out.should =~ /could not find gem 'missing'/i 40 | end 41 | end 42 | 43 | describe "bundle show with a git repo" do 44 | before :each do 45 | @git = build_git "foo", "1.0" 46 | end 47 | 48 | it "prints out git info" do 49 | install_gemfile <<-G 50 | gem "foo", :git => "#{lib_path('foo-1.0')}" 51 | G 52 | should_be_installed "foo 1.0" 53 | 54 | bundle :show 55 | out.should include("foo (1.0 #{@git.ref_for('master', 6)}") 56 | end 57 | 58 | it "prints out branch names other than master" do 59 | update_git "foo", :branch => "omg" do |s| 60 | s.write "lib/foo.rb", "FOO = '1.0.omg'" 61 | end 62 | @revision = revision_for(lib_path("foo-1.0"))[0...6] 63 | 64 | install_gemfile <<-G 65 | gem "foo", :git => "#{lib_path('foo-1.0')}", :branch => "omg" 66 | G 67 | should_be_installed "foo 1.0.omg" 68 | 69 | bundle :show 70 | out.should include("foo (1.0 #{@git.ref_for('omg', 6)}") 71 | end 72 | 73 | it "doesn't print the branch when tied to a ref" do 74 | sha = revision_for(lib_path("foo-1.0")) 75 | install_gemfile <<-G 76 | gem "foo", :git => "#{lib_path('foo-1.0')}", :ref => "#{sha}" 77 | G 78 | 79 | bundle :show 80 | out.should include("foo (1.0 #{sha[0..6]})") 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path('..', __FILE__) 2 | $:.unshift File.expand_path('../../lib', __FILE__) 3 | 4 | require 'fileutils' 5 | require 'rubygems' 6 | require 'bundler' 7 | require 'rspec' 8 | 9 | # Require the correct version of popen for the current platform 10 | if RbConfig::CONFIG['host_os'] =~ /mingw|mswin/ 11 | begin 12 | require 'win32/open3' 13 | rescue LoadError 14 | abort "Run `gem install win32-open3` to be able to run specs" 15 | end 16 | else 17 | require 'open3' 18 | end 19 | 20 | Dir["#{File.expand_path('../support', __FILE__)}/*.rb"].each do |file| 21 | require file 22 | end 23 | 24 | $debug = false 25 | $show_err = true 26 | 27 | Spec::Rubygems.setup 28 | FileUtils.rm_rf(Spec::Path.gem_repo1) 29 | ENV['RUBYOPT'] = "-I#{Spec::Path.root}/spec/support/rubygems_hax" 30 | ENV['BUNDLE_SPEC_RUN'] = "true" 31 | 32 | RSpec.configure do |config| 33 | config.include Spec::Builders 34 | config.include Spec::Helpers 35 | config.include Spec::Indexes 36 | config.include Spec::Matchers 37 | config.include Spec::Path 38 | config.include Spec::Rubygems 39 | config.include Spec::Platforms 40 | config.include Spec::Sudo 41 | 42 | config.filter_run :focused => true unless ENV['CI'] 43 | config.filter_run_excluding :sudo => true unless Spec::Sudo.test_sudo? 44 | config.run_all_when_everything_filtered = true 45 | config.alias_example_to :fit, :focused => true 46 | 47 | original_wd = Dir.pwd 48 | original_path = ENV['PATH'] 49 | original_gem_home = ENV['GEM_HOME'] 50 | 51 | def pending_jruby_shebang_fix 52 | pending "JRuby executables do not have a proper shebang" if RUBY_PLATFORM == "java" 53 | end 54 | 55 | def check(*args) 56 | # suppresses ruby warnings about "useless use of == in void context" 57 | # e.g. check foo.should == bar 58 | end 59 | 60 | config.before :all do 61 | build_repo1 62 | end 63 | 64 | config.before :each do 65 | reset! 66 | system_gems [] 67 | in_app_root 68 | end 69 | 70 | config.after :each do 71 | Dir.chdir(original_wd) 72 | # Reset ENV 73 | ENV['PATH'] = original_path 74 | ENV['GEM_HOME'] = original_gem_home 75 | ENV['GEM_PATH'] = original_gem_home 76 | ENV['BUNDLE_PATH'] = nil 77 | ENV['BUNDLE_GEMFILE'] = nil 78 | ENV['BUNDLER_TEST'] = nil 79 | ENV['BUNDLE_FROZEN'] = nil 80 | ENV['BUNDLER_SPEC_PLATFORM'] = nil 81 | ENV['BUNDLER_SPEC_VERSION'] = nil 82 | ENV['BUNDLE_APP_CONFIG'] = nil 83 | end 84 | end 85 | 86 | -------------------------------------------------------------------------------- /man/bundle-package.ronn: -------------------------------------------------------------------------------- 1 | bundle-package(1) -- Package your needed `.gem` files into your application 2 | =========================================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle package` 7 | 8 | ## DESCRIPTION 9 | 10 | Copy all of the `.gem` files needed to run the application into the 11 | `vendor/cache` directory. In the future, when running [bundle install(1)][bundle-install], 12 | use the gems in the cache in preference to the ones on `rubygems.org`. 13 | 14 | ## GIT AND PATH GEMS 15 | 16 | In Bundler 1.0, the `bundle package` command only packages `.gem` files, 17 | not gems specified using the `:git` or `:path` options. This will likely 18 | change in the future. 19 | 20 | ## REMOTE FETCHING 21 | 22 | By default, if you simply run [bundle install(1)][bundle-install] after running 23 | [bundle package(1)][bundle-package], bundler will still connect to `rubygems.org` 24 | to check whether a platform-specific gem exists for any of the gems 25 | in `vendor/cache`. 26 | 27 | For instance, consider this Gemfile(5): 28 | 29 | source "http://rubygems.org" 30 | 31 | gem "nokogiri" 32 | 33 | If you run `bundle package` under C Ruby, bundler will retrieve 34 | the version of `nokogiri` for the `"ruby"` platform. If you deploy 35 | to JRuby and run `bundle install`, bundler is forced to check to 36 | see whether a `"java"` platformed `nokogiri` exists. 37 | 38 | Even though the `nokogiri` gem for the Ruby platform is 39 | _technically_ acceptable on JRuby, it actually has a C extension 40 | that does not run on JRuby. As a result, bundler will, by default, 41 | still connect to `rubygems.org` to check whether it has a version 42 | of one of your gems more specific to your platform. 43 | 44 | This problem is also not just limited to the `"java"` platform. 45 | A similar (common) problem can happen when developing on Windows 46 | and deploying to Linux, or even when developing on OSX and 47 | deploying to Linux. 48 | 49 | If you know for sure that the gems packaged in `vendor/cache` 50 | are appropriate for the platform you are on, you can run 51 | `bundle install --local` to skip checking for more appropriate 52 | gems, and just use the ones in `vendor/cache`. 53 | 54 | One way to be sure that you have the right platformed versions 55 | of all your gems is to run `bundle package` on an identical 56 | machine and check in the gems. For instance, you can run 57 | `bundle package` on an identical staging box during your 58 | staging process, and check in the `vendor/cache` before 59 | deploying to production. 60 | -------------------------------------------------------------------------------- /lib/bundler/deployment.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class Deployment 3 | def self.define_task(context, task_method = :task, opts = {}) 4 | if context.is_a?(Capistrano::Configuration) 5 | context_name = "capistrano" 6 | role_default = "{:except => {:no_release => true}}" 7 | else 8 | context_name = "vlad" 9 | role_default = "[:app]" 10 | end 11 | 12 | roles = context.fetch(:bundle_roles, nil) 13 | opts[:roles] = roles if roles 14 | 15 | context.send :namespace, :bundle do 16 | send :desc, <<-DESC 17 | Install the current Bundler environment. By default, gems will be \ 18 | installed to the shared/bundle path. Gems in the development and \ 19 | test group will not be installed. The install command is executed \ 20 | with the --deployment and --quiet flags. If the bundle cmd cannot \ 21 | be found then you can override the bundle_cmd variable to specifiy \ 22 | which one it should use. 23 | 24 | You can override any of these defaults by setting the variables shown below. 25 | 26 | N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ 27 | in your deploy.rb file. 28 | 29 | set :bundle_gemfile, "Gemfile" 30 | set :bundle_dir, File.join(fetch(:shared_path), 'bundle') 31 | set :bundle_flags, "--deployment --quiet" 32 | set :bundle_without, [:development, :test] 33 | set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" 34 | set :bundle_roles, #{role_default} # e.g. [:app, :batch] 35 | DESC 36 | send task_method, :install, opts do 37 | bundle_cmd = context.fetch(:bundle_cmd, "bundle") 38 | bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") 39 | bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), 'bundle')) 40 | bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") 41 | bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact 42 | 43 | args = ["--gemfile #{File.join(context.fetch(:current_release), bundle_gemfile)}"] 44 | args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? 45 | args << bundle_flags.to_s 46 | args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? 47 | 48 | run "#{bundle_cmd} install #{args.join(' ')}" 49 | end 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/shell.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig' 2 | 3 | class Thor 4 | module Base 5 | # Returns the shell used in all Thor classes. If you are in a Unix platform 6 | # it will use a colored log, otherwise it will use a basic one without color. 7 | # 8 | def self.shell 9 | @shell ||= if ENV['THOR_SHELL'] && ENV['THOR_SHELL'].size > 0 10 | Thor::Shell.const_get(ENV['THOR_SHELL']) 11 | elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ 12 | Thor::Shell::Basic 13 | else 14 | Thor::Shell::Color 15 | end 16 | end 17 | 18 | # Sets the shell used in all Thor classes. 19 | # 20 | def self.shell=(klass) 21 | @shell = klass 22 | end 23 | end 24 | 25 | module Shell 26 | SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table] 27 | 28 | autoload :Basic, 'thor/shell/basic' 29 | autoload :Color, 'thor/shell/color' 30 | autoload :HTML, 'thor/shell/html' 31 | 32 | # Add shell to initialize config values. 33 | # 34 | # ==== Configuration 35 | # shell:: An instance of the shell to be used. 36 | # 37 | # ==== Examples 38 | # 39 | # class MyScript < Thor 40 | # argument :first, :type => :numeric 41 | # end 42 | # 43 | # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new 44 | # 45 | def initialize(args=[], options={}, config={}) 46 | super 47 | self.shell = config[:shell] 48 | self.shell.base ||= self if self.shell.respond_to?(:base) 49 | end 50 | 51 | # Holds the shell for the given Thor instance. If no shell is given, 52 | # it gets a default shell from Thor::Base.shell. 53 | def shell 54 | @shell ||= Thor::Base.shell.new 55 | end 56 | 57 | # Sets the shell for this thor class. 58 | def shell=(shell) 59 | @shell = shell 60 | end 61 | 62 | # Common methods that are delegated to the shell. 63 | SHELL_DELEGATED_METHODS.each do |method| 64 | module_eval <<-METHOD, __FILE__, __LINE__ 65 | def #{method}(*args) 66 | shell.#{method}(*args) 67 | end 68 | METHOD 69 | end 70 | 71 | # Yields the given block with padding. 72 | def with_padding 73 | shell.padding += 1 74 | yield 75 | ensure 76 | shell.padding -= 1 77 | end 78 | 79 | protected 80 | 81 | # Allow shell to be shared between invocations. 82 | # 83 | def _shared_configuration #:nodoc: 84 | super.merge!(:shell => self.shell) 85 | end 86 | 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/core_ext/ordered_hash.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | module CoreExt #:nodoc: 3 | 4 | if RUBY_VERSION >= '1.9' 5 | class OrderedHash < ::Hash 6 | end 7 | else 8 | # This class is based on the Ruby 1.9 ordered hashes. 9 | # 10 | # It keeps the semantics and most of the efficiency of normal hashes 11 | # while also keeping track of the order in which elements were set. 12 | # 13 | class OrderedHash #:nodoc: 14 | include Enumerable 15 | 16 | Node = Struct.new(:key, :value, :next, :prev) 17 | 18 | def initialize 19 | @hash = {} 20 | end 21 | 22 | def [](key) 23 | @hash[key] && @hash[key].value 24 | end 25 | 26 | def []=(key, value) 27 | if node = @hash[key] 28 | node.value = value 29 | else 30 | node = Node.new(key, value) 31 | 32 | if @first.nil? 33 | @first = @last = node 34 | else 35 | node.prev = @last 36 | @last.next = node 37 | @last = node 38 | end 39 | end 40 | 41 | @hash[key] = node 42 | value 43 | end 44 | 45 | def delete(key) 46 | if node = @hash[key] 47 | prev_node = node.prev 48 | next_node = node.next 49 | 50 | next_node.prev = prev_node if next_node 51 | prev_node.next = next_node if prev_node 52 | 53 | @first = next_node if @first == node 54 | @last = prev_node if @last == node 55 | 56 | value = node.value 57 | end 58 | 59 | @hash.delete(key) 60 | value 61 | end 62 | 63 | def keys 64 | self.map { |k, v| k } 65 | end 66 | 67 | def values 68 | self.map { |k, v| v } 69 | end 70 | 71 | def each 72 | return unless @first 73 | yield [@first.key, @first.value] 74 | node = @first 75 | yield [node.key, node.value] while node = node.next 76 | self 77 | end 78 | 79 | def merge(other) 80 | hash = self.class.new 81 | 82 | self.each do |key, value| 83 | hash[key] = value 84 | end 85 | 86 | other.each do |key, value| 87 | hash[key] = value 88 | end 89 | 90 | hash 91 | end 92 | 93 | def empty? 94 | @hash.empty? 95 | end 96 | end 97 | end 98 | 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /spec/runtime/executable_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Running bin/* commands" do 4 | before :each do 5 | gemfile <<-G 6 | source "file://#{gem_repo1}" 7 | gem "rack" 8 | G 9 | end 10 | 11 | it "runs the bundled command when in the bundle" do 12 | bundle "install --binstubs" 13 | 14 | build_gem "rack", "2.0", :to_system => true do |s| 15 | s.executables = "rackup" 16 | end 17 | 18 | gembin "rackup" 19 | out.should == "1.0.0" 20 | end 21 | 22 | it "allows the location of the gem stubs to be specified" do 23 | bundle "install --binstubs gbin" 24 | 25 | bundled_app("bin").should_not exist 26 | bundled_app("gbin/rackup").should exist 27 | 28 | gembin bundled_app("gbin/rackup") 29 | out.should == "1.0.0" 30 | end 31 | 32 | it "allows absolute paths as a specification of where to install bin stubs" do 33 | bundle "install --binstubs #{tmp}/bin" 34 | 35 | gembin tmp("bin/rackup") 36 | out.should == "1.0.0" 37 | end 38 | 39 | it "runs the bundled command when out of the bundle" do 40 | bundle "install --binstubs" 41 | 42 | build_gem "rack", "2.0", :to_system => true do |s| 43 | s.executables = "rackup" 44 | end 45 | 46 | Dir.chdir(tmp) do 47 | gembin "rackup" 48 | out.should == "1.0.0" 49 | end 50 | end 51 | 52 | it "works with gems in path" do 53 | build_lib "rack", :path => lib_path("rack") do |s| 54 | s.executables = 'rackup' 55 | end 56 | 57 | gemfile <<-G 58 | gem "rack", :path => "#{lib_path('rack')}" 59 | G 60 | 61 | bundle "install --binstubs" 62 | 63 | build_gem 'rack', '2.0', :to_system => true do |s| 64 | s.executables = 'rackup' 65 | end 66 | 67 | gembin "rackup" 68 | out.should == '1.0' 69 | end 70 | 71 | it "don't bundle da bundla" do 72 | build_gem "bundler", Bundler::VERSION, :to_system => true do |s| 73 | s.executables = "bundle" 74 | end 75 | 76 | gemfile <<-G 77 | source "file://#{gem_repo1}" 78 | gem "bundler" 79 | G 80 | 81 | bundle "install --binstubs" 82 | 83 | bundled_app("bin/bundle").should_not exist 84 | end 85 | 86 | it "does not generate bin stubs if the option was not specified" do 87 | bundle "install" 88 | 89 | bundled_app("bin/rackup").should_not exist 90 | end 91 | 92 | it "remembers that the option was specified" do 93 | gemfile <<-G 94 | source "file://#{gem_repo1}" 95 | gem "activesupport" 96 | G 97 | 98 | bundle "install --binstubs" 99 | 100 | gemfile <<-G 101 | source "file://#{gem_repo1}" 102 | gem "activesupport" 103 | gem "rack" 104 | G 105 | 106 | bundle "install" 107 | 108 | bundled_app("bin/rackup").should exist 109 | end 110 | end -------------------------------------------------------------------------------- /lib/bundler/installer.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | require 'rubygems/dependency_installer' 3 | 4 | module Bundler 5 | class Installer < Environment 6 | def self.install(root, definition, options = {}) 7 | installer = new(root, definition) 8 | installer.run(options) 9 | installer 10 | end 11 | 12 | def run(options) 13 | if Bundler.settings[:frozen] 14 | @definition.ensure_equivalent_gemfile_and_lockfile 15 | end 16 | 17 | if dependencies.empty? 18 | Bundler.ui.warn "The Gemfile specifies no dependencies" 19 | return 20 | end 21 | 22 | if Bundler.default_lockfile.exist? && !options["update"] 23 | begin 24 | tmpdef = Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, nil) 25 | local = true unless tmpdef.new_platform? || tmpdef.missing_specs.any? 26 | rescue BundlerError 27 | end 28 | end 29 | 30 | # Since we are installing, we can resolve the definition 31 | # using remote specs 32 | unless local 33 | options["local"] ? 34 | @definition.resolve_with_cache! : 35 | @definition.resolve_remotely! 36 | end 37 | 38 | # Ensure that BUNDLE_PATH exists 39 | Bundler.mkdir_p(Bundler.bundle_path) unless File.exist?(Bundler.bundle_path) 40 | 41 | # Must install gems in the order that the resolver provides 42 | # as dependencies might actually affect the installation of 43 | # the gem. 44 | specs.each do |spec| 45 | spec.source.fetch(spec) if spec.source.respond_to?(:fetch) 46 | 47 | # unless requested_specs.include?(spec) 48 | # Bundler.ui.debug " * Not in requested group; skipping." 49 | # next 50 | # end 51 | 52 | begin 53 | old_args = Gem::Command.build_args 54 | Gem::Command.build_args = [Bundler.settings["build.#{spec.name}"]] 55 | spec.source.install(spec) 56 | Bundler.ui.debug "from #{spec.loaded_from} " 57 | ensure 58 | Gem::Command.build_args = old_args 59 | end 60 | 61 | Bundler.ui.info "" 62 | generate_bundler_executable_stubs(spec) if Bundler.settings[:bin] 63 | FileUtils.rm_rf(Bundler.tmp) 64 | end 65 | 66 | lock 67 | end 68 | 69 | private 70 | 71 | def generate_bundler_executable_stubs(spec) 72 | bin_path = Bundler.bin_path 73 | template = File.read(File.expand_path('../templates/Executable', __FILE__)) 74 | relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) 75 | ruby_command = Thor::Util.ruby_command 76 | 77 | spec.executables.each do |executable| 78 | next if executable == "bundle" 79 | File.open "#{bin_path}/#{executable}", 'w', 0755 do |f| 80 | f.puts ERB.new(template, nil, '-').result(binding) 81 | end 82 | end 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/update/gems_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle update" do 4 | before :each do 5 | build_repo2 6 | 7 | install_gemfile <<-G 8 | source "file://#{gem_repo2}" 9 | gem "activesupport" 10 | gem "rack-obama" 11 | G 12 | end 13 | 14 | describe "with no arguments" do 15 | it "updates the entire bundle" do 16 | update_repo2 do 17 | build_gem "activesupport", "3.0" 18 | end 19 | 20 | bundle "update" 21 | should_be_installed "rack 1.2", "rack-obama 1.0", "activesupport 3.0" 22 | end 23 | 24 | it "doesn't delete the Gemfile.lock file if something goes wrong" do 25 | gemfile <<-G 26 | source "file://#{gem_repo2}" 27 | gem "activesupport" 28 | gem "rack-obama" 29 | exit! 30 | G 31 | bundle "update" 32 | bundled_app("Gemfile.lock").should exist 33 | end 34 | end 35 | 36 | describe "with a top level dependency" do 37 | it "unlocks all child dependencies that are unrelated to other locked dependencies" do 38 | update_repo2 do 39 | build_gem "activesupport", "3.0" 40 | end 41 | 42 | bundle "update rack-obama" 43 | should_be_installed "rack 1.2", "rack-obama 1.0", "activesupport 2.3.5" 44 | end 45 | end 46 | end 47 | 48 | describe "bundle update in more complicated situations" do 49 | before :each do 50 | build_repo2 51 | end 52 | 53 | it "will eagerly unlock dependencies of a specified gem" do 54 | install_gemfile <<-G 55 | source "file://#{gem_repo2}" 56 | 57 | gem "thin" 58 | gem "rack-obama" 59 | G 60 | 61 | update_repo2 do 62 | build_gem "thin" , '2.0' do |s| 63 | s.add_dependency "rack" 64 | end 65 | end 66 | 67 | bundle "update thin" 68 | should_be_installed "thin 2.0", "rack 1.2", "rack-obama 1.0" 69 | end 70 | end 71 | 72 | describe "bundle update without a Gemfile.lock" do 73 | it "should not explode" do 74 | build_repo2 75 | 76 | gemfile <<-G 77 | source "file://#{gem_repo2}" 78 | 79 | gem "rack", "1.0" 80 | G 81 | 82 | bundle "update" 83 | 84 | should_be_installed "rack 1.0.0" 85 | end 86 | end 87 | 88 | describe "bundle update when a gem depends on a newer version of bundler" do 89 | before(:each) do 90 | build_repo2 do 91 | build_gem "rails", "3.0.1" do |s| 92 | s.add_dependency "bundler", Bundler::VERSION.succ 93 | end 94 | end 95 | 96 | gemfile <<-G 97 | source "file://#{gem_repo2}" 98 | gem "rails", "3.0.1" 99 | G 100 | end 101 | 102 | it "should not explode" do 103 | bundle "update" 104 | err.should be_empty 105 | end 106 | 107 | it "should explain that bundler conflicted" do 108 | bundle "update" 109 | out.should_not =~ /In snapshot/ 110 | out.should =~ /Current Bundler version/ 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /spec/support/matchers.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Matchers 3 | RSpec::Matchers.define :have_dep do |*args| 4 | dep = Bundler::Dependency.new(*args) 5 | 6 | match do |actual| 7 | actual.length == 1 && actual.all? { |d| d == dep } 8 | end 9 | end 10 | 11 | RSpec::Matchers.define :have_gem do |*args| 12 | match do |actual| 13 | actual.length == args.length && actual.all? { |a| args.include?(a.full_name) } 14 | end 15 | end 16 | 17 | RSpec::Matchers.define :have_rubyopts do |*args| 18 | args = args.flatten 19 | args = args.first.split(/\s+/) if args.size == 1 20 | 21 | #failure_message_for_should "Expected RUBYOPT to have options #{args.join(" ")}. It was #{ENV["RUBYOPT"]}" 22 | 23 | match do |actual| 24 | actual = actual.split(/\s+/) if actual.is_a?(String) 25 | args.all? {|arg| actual.include?(arg) } && actual.uniq.size == actual.size 26 | end 27 | end 28 | 29 | def should_be_installed(*names) 30 | opts = names.last.is_a?(Hash) ? names.pop : {} 31 | groups = Array(opts[:groups]) 32 | groups << opts 33 | names.each do |name| 34 | name, version, platform = name.split(/\s+/) 35 | version_const = name == 'bundler' ? 'Bundler::VERSION' : Spec::Builders.constantize(name) 36 | run "require '#{name}.rb'; puts #{version_const}", *groups 37 | actual_version, actual_platform = out.split(/\s+/) 38 | check Gem::Version.new(actual_version).should == Gem::Version.new(version) 39 | actual_platform.should == platform 40 | end 41 | end 42 | 43 | alias should_be_available should_be_installed 44 | 45 | def should_not_be_installed(*names) 46 | opts = names.last.is_a?(Hash) ? names.pop : {} 47 | groups = Array(opts[:groups]) || [] 48 | names.each do |name| 49 | name, version = name.split(/\s+/) 50 | run <<-R, *(groups + [opts]) 51 | begin 52 | require '#{name}' 53 | puts #{Spec::Builders.constantize(name)} 54 | rescue LoadError, NameError 55 | puts "WIN" 56 | end 57 | R 58 | if version.nil? || out == "WIN" 59 | out.should == "WIN" 60 | else 61 | Gem::Version.new(out).should_not == Gem::Version.new(version) 62 | end 63 | end 64 | end 65 | 66 | def should_be_locked 67 | bundled_app("Gemfile.lock").should exist 68 | end 69 | 70 | RSpec::Matchers.define :be_with_diff do |expected| 71 | spaces = expected[/\A\s+/, 0] || "" 72 | expected.gsub!(/^#{spaces}/, '') 73 | 74 | failure_message_for_should do |actual| 75 | "The lockfile did not match.\n=== Expected:\n" << 76 | expected << "\n=== Got:\n" << actual << "\n===========\n" 77 | end 78 | 79 | match do |actual| 80 | expected == actual 81 | end 82 | end 83 | 84 | def lockfile_should_be(expected) 85 | lock = File.read(bundled_app("Gemfile.lock")) 86 | lock.should be_with_diff(expected) 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/install/gems/env_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install with ENV conditionals" do 4 | describe "when just setting an ENV key as a string" do 5 | before :each do 6 | gemfile <<-G 7 | source "file://#{gem_repo1}" 8 | 9 | env "BUNDLER_TEST" do 10 | gem "rack" 11 | end 12 | G 13 | end 14 | 15 | it "excludes the gems when the ENV variable is not set" do 16 | bundle :install 17 | should_not_be_installed "rack" 18 | end 19 | 20 | it "includes the gems when the ENV variable is set" do 21 | ENV['BUNDLER_TEST'] = '1' 22 | bundle :install 23 | should_be_installed "rack 1.0" 24 | end 25 | end 26 | 27 | describe "when just setting an ENV key as a symbol" do 28 | before :each do 29 | gemfile <<-G 30 | source "file://#{gem_repo1}" 31 | 32 | env :BUNDLER_TEST do 33 | gem "rack" 34 | end 35 | G 36 | end 37 | 38 | it "excludes the gems when the ENV variable is not set" do 39 | bundle :install 40 | should_not_be_installed "rack" 41 | end 42 | 43 | it "includes the gems when the ENV variable is set" do 44 | ENV['BUNDLER_TEST'] = '1' 45 | bundle :install 46 | should_be_installed "rack 1.0" 47 | end 48 | end 49 | 50 | describe "when setting a string to match the env" do 51 | before :each do 52 | gemfile <<-G 53 | source "file://#{gem_repo1}" 54 | 55 | env "BUNDLER_TEST" => "foo" do 56 | gem "rack" 57 | end 58 | G 59 | end 60 | 61 | it "excludes the gems when the ENV variable is not set" do 62 | bundle :install 63 | should_not_be_installed "rack" 64 | end 65 | 66 | it "excludes the gems when the ENV variable is set but does not match the condition" do 67 | ENV['BUNDLER_TEST'] = '1' 68 | bundle :install 69 | should_not_be_installed "rack" 70 | end 71 | 72 | it "includes the gems when the ENV variable is set and matches the condition" do 73 | ENV['BUNDLER_TEST'] = 'foo' 74 | bundle :install 75 | should_be_installed "rack 1.0" 76 | end 77 | end 78 | 79 | describe "when setting a regex to match the env" do 80 | before :each do 81 | gemfile <<-G 82 | source "file://#{gem_repo1}" 83 | 84 | env "BUNDLER_TEST" => /foo/ do 85 | gem "rack" 86 | end 87 | G 88 | end 89 | 90 | it "excludes the gems when the ENV variable is not set" do 91 | bundle :install 92 | should_not_be_installed "rack" 93 | end 94 | 95 | it "excludes the gems when the ENV variable is set but does not match the condition" do 96 | ENV['BUNDLER_TEST'] = 'fo' 97 | bundle :install 98 | should_not_be_installed "rack" 99 | end 100 | 101 | it "includes the gems when the ENV variable is set and matches the condition" do 102 | ENV['BUNDLER_TEST'] = 'foobar' 103 | bundle :install 104 | should_be_installed "rack 1.0" 105 | end 106 | end 107 | end -------------------------------------------------------------------------------- /spec/runtime/load_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "Bundler.load" do 4 | before :each do 5 | system_gems "rack-1.0.0" 6 | # clear memoized method results 7 | # TODO: Don't reset internal ivars 8 | Bundler.instance_eval do 9 | @load = nil 10 | @runtime = nil 11 | @definition = nil 12 | end 13 | end 14 | 15 | describe "with a gemfile" do 16 | before(:each) do 17 | gemfile <<-G 18 | source "file://#{gem_repo1}" 19 | gem "rack" 20 | G 21 | end 22 | 23 | it "provides a list of the env dependencies" do 24 | Bundler.load.dependencies.should have_dep("rack", ">= 0") 25 | end 26 | 27 | it "provides a list of the resolved gems" do 28 | Bundler.load.gems.should have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}") 29 | end 30 | 31 | it "ignores blank BUNDLE_GEMFILEs" do 32 | lambda { 33 | ENV['BUNDLE_GEMFILE'] = "" 34 | Bundler.load 35 | }.should_not raise_error(Bundler::GemfileNotFound) 36 | end 37 | 38 | end 39 | 40 | describe "without a gemfile" do 41 | it "raises an exception if the default gemfile is not found" do 42 | lambda { 43 | Bundler.load 44 | }.should raise_error(Bundler::GemfileNotFound, /could not locate gemfile/i) 45 | end 46 | 47 | it "raises an exception if a specified gemfile is not found" do 48 | lambda { 49 | ENV['BUNDLE_GEMFILE'] = "omg.rb" 50 | Bundler.load 51 | }.should raise_error(Bundler::GemfileNotFound, /omg\.rb/) 52 | end 53 | 54 | it "does not find a Gemfile above the testing directory" do 55 | bundler_gemfile = tmp.join("../Gemfile") 56 | unless File.exists?(bundler_gemfile) 57 | FileUtils.touch(bundler_gemfile) 58 | @remove_bundler_gemfile = true 59 | end 60 | begin 61 | lambda { Bundler.load }.should raise_error(Bundler::GemfileNotFound) 62 | ensure 63 | bundler_gemfile.rmtree if @remove_bundler_gemfile 64 | end 65 | end 66 | 67 | end 68 | 69 | describe "when called twice" do 70 | it "doesn't try to load the runtime twice" do 71 | system_gems "rack-1.0.0", "activesupport-2.3.5" 72 | gemfile <<-G 73 | gem "rack" 74 | gem "activesupport", :group => :test 75 | G 76 | 77 | ruby <<-RUBY 78 | require "bundler" 79 | Bundler.setup :default 80 | Bundler.require :default 81 | puts RACK 82 | begin 83 | require "activesupport" 84 | rescue LoadError 85 | puts "no activesupport" 86 | end 87 | RUBY 88 | 89 | out.split("\n").should == ["1.0.0", "no activesupport"] 90 | end 91 | end 92 | 93 | describe "not hurting brittle rubygems" do 94 | it "does not inject #source into the generated YAML of the gem specs" do 95 | system_gems "activerecord-2.3.2", "activesupport-2.3.2" 96 | gemfile <<-G 97 | gem "activerecord" 98 | G 99 | 100 | Bundler.load.specs.each do |spec| 101 | spec.to_yaml.should_not =~ /^\s+source:/ 102 | spec.to_yaml.should_not =~ /^\s+groups:/ 103 | end 104 | end 105 | end 106 | 107 | end 108 | -------------------------------------------------------------------------------- /spec/install/gemspec_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install from an existing gemspec" do 4 | 5 | before(:each) do 6 | build_gem "bar", :to_system => true 7 | build_gem "bar-dev", :to_system => true 8 | end 9 | 10 | it "should install runtime and development dependencies" do 11 | build_lib("foo", :path => tmp.join("foo")) do |s| 12 | s.write("Gemfile", "source :rubygems\ngemspec") 13 | s.add_dependency "bar", "=1.0.0" 14 | s.add_development_dependency "bar-dev", '=1.0.0' 15 | end 16 | install_gemfile <<-G 17 | source "file://#{gem_repo2}" 18 | gemspec :path => '#{tmp.join("foo")}' 19 | G 20 | 21 | should_be_installed "bar 1.0.0" 22 | should_be_installed "bar-dev 1.0.0", :groups => :development 23 | end 24 | 25 | it "should handle a list of requirements" do 26 | build_gem "baz", "1.0", :to_system => true 27 | build_gem "baz", "1.1", :to_system => true 28 | 29 | build_lib("foo", :path => tmp.join("foo")) do |s| 30 | s.write("Gemfile", "source :rubygems\ngemspec") 31 | s.add_dependency "baz", ">= 1.0", "< 1.1" 32 | end 33 | install_gemfile <<-G 34 | source "file://#{gem_repo2}" 35 | gemspec :path => '#{tmp.join("foo")}' 36 | G 37 | 38 | should_be_installed "baz 1.0" 39 | end 40 | 41 | it "should raise if there are no gemspecs available" do 42 | build_lib("foo", :path => tmp.join("foo"), :gemspec => false) 43 | 44 | error = install_gemfile(<<-G, :expect_err => true) 45 | source "file://#{gem_repo2}" 46 | gemspec :path => '#{tmp.join("foo")}' 47 | G 48 | error.should match(/There are no gemspecs at #{tmp.join('foo')}/) 49 | end 50 | 51 | it "should raise if there are too many gemspecs available" do 52 | build_lib("foo", :path => tmp.join("foo")) do |s| 53 | s.write("foo2.gemspec", "") 54 | end 55 | 56 | error = install_gemfile(<<-G, :expect_err => true) 57 | source "file://#{gem_repo2}" 58 | gemspec :path => '#{tmp.join("foo")}' 59 | G 60 | error.should match(/There are multiple gemspecs at #{tmp.join('foo')}/) 61 | end 62 | 63 | it "should pick a specific gemspec" do 64 | build_lib("foo", :path => tmp.join("foo")) do |s| 65 | s.write("foo2.gemspec", "") 66 | s.add_dependency "bar", "=1.0.0" 67 | s.add_development_dependency "bar-dev", '=1.0.0' 68 | end 69 | 70 | install_gemfile(<<-G, :expect_err => true) 71 | source "file://#{gem_repo2}" 72 | gemspec :path => '#{tmp.join("foo")}', :name => 'foo' 73 | G 74 | 75 | should_be_installed "bar 1.0.0" 76 | should_be_installed "bar-dev 1.0.0", :groups => :development 77 | end 78 | 79 | it "should use a specific group for development dependencies" do 80 | build_lib("foo", :path => tmp.join("foo")) do |s| 81 | s.write("foo2.gemspec", "") 82 | s.add_dependency "bar", "=1.0.0" 83 | s.add_development_dependency "bar-dev", '=1.0.0' 84 | end 85 | 86 | install_gemfile(<<-G, :expect_err => true) 87 | source "file://#{gem_repo2}" 88 | gemspec :path => '#{tmp.join("foo")}', :name => 'foo', :development_group => :dev 89 | G 90 | 91 | should_be_installed "bar 1.0.0" 92 | should_not_be_installed "bar-dev 1.0.0", :groups => :development 93 | should_be_installed "bar-dev 1.0.0", :groups => :dev 94 | end 95 | 96 | end 97 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/actions/directory.rb: -------------------------------------------------------------------------------- 1 | require 'thor/actions/empty_directory' 2 | 3 | class Thor 4 | module Actions 5 | 6 | # Copies recursively the files from source directory to root directory. 7 | # If any of the files finishes with .tt, it's considered to be a template 8 | # and is placed in the destination without the extension .tt. If any 9 | # empty directory is found, it's copied and all .empty_directory files are 10 | # ignored. Remember that file paths can also be encoded, let's suppose a doc 11 | # directory with the following files: 12 | # 13 | # doc/ 14 | # components/.empty_directory 15 | # README 16 | # rdoc.rb.tt 17 | # %app_name%.rb 18 | # 19 | # When invoked as: 20 | # 21 | # directory "doc" 22 | # 23 | # It will create a doc directory in the destination with the following 24 | # files (assuming that the app_name is "blog"): 25 | # 26 | # doc/ 27 | # components/ 28 | # README 29 | # rdoc.rb 30 | # blog.rb 31 | # 32 | # ==== Parameters 33 | # source:: the relative path to the source root. 34 | # destination:: the relative path to the destination root. 35 | # config:: give :verbose => false to not log the status. 36 | # If :recursive => false, does not look for paths recursively. 37 | # 38 | # ==== Examples 39 | # 40 | # directory "doc" 41 | # directory "doc", "docs", :recursive => false 42 | # 43 | def directory(source, *args, &block) 44 | config = args.last.is_a?(Hash) ? args.pop : {} 45 | destination = args.first || source 46 | action Directory.new(self, source, destination || source, config, &block) 47 | end 48 | 49 | class Directory < EmptyDirectory #:nodoc: 50 | attr_reader :source 51 | 52 | def initialize(base, source, destination=nil, config={}, &block) 53 | @source = File.expand_path(base.find_in_source_paths(source.to_s)) 54 | @block = block 55 | super(base, destination, { :recursive => true }.merge(config)) 56 | end 57 | 58 | def invoke! 59 | base.empty_directory given_destination, config 60 | execute! 61 | end 62 | 63 | def revoke! 64 | execute! 65 | end 66 | 67 | protected 68 | 69 | def execute! 70 | lookup = config[:recursive] ? File.join(source, '**') : source 71 | lookup = File.join(lookup, '{*,.[a-z]*}') 72 | 73 | Dir[lookup].each do |file_source| 74 | next if File.directory?(file_source) 75 | file_destination = File.join(given_destination, file_source.gsub(source, '.')) 76 | file_destination.gsub!('/./', '/') 77 | 78 | case file_source 79 | when /\.empty_directory$/ 80 | dirname = File.dirname(file_destination).gsub(/\/\.$/, '') 81 | next if dirname == given_destination 82 | base.empty_directory(dirname, config) 83 | when /\.tt$/ 84 | destination = base.template(file_source, file_destination[0..-4], config, &@block) 85 | else 86 | destination = base.copy_file(file_source, file_destination, config, &@block) 87 | end 88 | end 89 | end 90 | 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /lib/bundler/dependency.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/dependency' 2 | require 'bundler/shared_helpers' 3 | require 'bundler/rubygems_ext' 4 | 5 | module Bundler 6 | class Dependency < Gem::Dependency 7 | attr_reader :autorequire 8 | attr_reader :groups 9 | attr_reader :platforms 10 | 11 | PLATFORM_MAP = { 12 | :ruby => Gem::Platform::RUBY, 13 | :ruby_18 => Gem::Platform::RUBY, 14 | :ruby_19 => Gem::Platform::RUBY, 15 | :mri => Gem::Platform::RUBY, 16 | :mri_18 => Gem::Platform::RUBY, 17 | :mri_19 => Gem::Platform::RUBY, 18 | :jruby => Gem::Platform::JAVA, 19 | :mswin => Gem::Platform::MSWIN, 20 | :mingw => Gem::Platform::MINGW, 21 | :mingw_18 => Gem::Platform::MINGW, 22 | :mingw_19 => Gem::Platform::MINGW 23 | }.freeze 24 | 25 | def initialize(name, version, options = {}, &blk) 26 | super(name, version) 27 | 28 | @autorequire = nil 29 | @groups = Array(options["group"] || :default).map { |g| g.to_sym } 30 | @source = options["source"] 31 | @platforms = Array(options["platforms"]) 32 | @env = options["env"] 33 | 34 | if options.key?('require') 35 | @autorequire = Array(options['require'] || []) 36 | end 37 | end 38 | 39 | def gem_platforms(valid_platforms) 40 | return valid_platforms if @platforms.empty? 41 | 42 | platforms = [] 43 | @platforms.each do |p| 44 | platform = PLATFORM_MAP[p] 45 | next unless valid_platforms.include?(platform) 46 | platforms |= [platform] 47 | end 48 | platforms 49 | end 50 | 51 | def should_include? 52 | current_env? && current_platform? 53 | end 54 | 55 | def current_env? 56 | return true unless @env 57 | if Hash === @env 58 | @env.all? do |key, val| 59 | ENV[key.to_s] && (String === val ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) 60 | end 61 | else 62 | ENV[@env.to_s] 63 | end 64 | end 65 | 66 | def current_platform? 67 | return true if @platforms.empty? 68 | @platforms.any? { |p| send("#{p}?") } 69 | end 70 | 71 | def to_lock 72 | out = " #{name}" 73 | 74 | unless requirement == Gem::Requirement.default 75 | out << " (#{requirement.to_s})" 76 | end 77 | 78 | out << '!' if source 79 | 80 | out << "\n" 81 | end 82 | 83 | private 84 | 85 | def ruby? 86 | !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx") 87 | end 88 | 89 | def ruby_18? 90 | ruby? && RUBY_VERSION < "1.9" 91 | end 92 | 93 | def ruby_19? 94 | ruby? && RUBY_VERSION >= "1.9" 95 | end 96 | 97 | def mri? 98 | !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby") 99 | end 100 | 101 | def mri_18? 102 | mri? && RUBY_VERSION < "1.9" 103 | end 104 | 105 | def mri_19? 106 | mri? && RUBY_VERSION >= "1.9" 107 | end 108 | 109 | def jruby? 110 | defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" 111 | end 112 | 113 | def mswin? 114 | Bundler::WINDOWS 115 | end 116 | 117 | def mingw? 118 | Bundler::WINDOWS && Gem::Platform.local.os == "mingw32" 119 | end 120 | 121 | def mingw_18? 122 | mingw? && RUBY_VERSION < "1.9" 123 | end 124 | 125 | def mingw_19? 126 | mingw? && RUBY_VERSION >= "1.9" 127 | end 128 | 129 | end 130 | end 131 | -------------------------------------------------------------------------------- /lib/bundler/settings.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class Settings 3 | def initialize(root) 4 | @root = root 5 | @local_config = File.exist?(local_config_file) ? YAML.load_file(local_config_file) : {} 6 | @global_config = File.exist?(global_config_file) ? YAML.load_file(global_config_file) : {} 7 | end 8 | 9 | def [](key) 10 | key = key_for(key) 11 | @local_config[key] || ENV[key] || @global_config[key] 12 | end 13 | 14 | def []=(key, value) 15 | set_key(key, value, @local_config, local_config_file) 16 | end 17 | 18 | def delete(key) 19 | @local_config 20 | end 21 | 22 | def set_global(key, value) 23 | set_key(key, value, @global_config, global_config_file) 24 | end 25 | 26 | def all 27 | env_keys = ENV.keys.select { |k| k =~ /BUNDLE_.*/ } 28 | keys = @global_config.keys | @local_config.keys | env_keys 29 | 30 | keys.map do |key| 31 | key.sub(/^BUNDLE_/, '').gsub(/__/, ".").downcase 32 | end 33 | end 34 | 35 | def locations(key) 36 | locations = {} 37 | 38 | locations[:local] = @local_config[key] if @local_config.key?(key) 39 | locations[:env] = ENV[key] if ENV[key] 40 | locations[:global] = @global_config[key] if @global_config.key?(key) 41 | locations 42 | end 43 | 44 | def pretty_values_for(exposed_key) 45 | key = key_for(exposed_key) 46 | 47 | locations = [] 48 | if @local_config.key?(key) 49 | locations << "Set for your local app (#{local_config_file}): #{@local_config[key].inspect}" 50 | end 51 | 52 | if value = ENV[key] 53 | locations << "Set via #{key}: #{value.inspect}" 54 | end 55 | 56 | if @global_config.key?(key) 57 | locations << "Set for the current user (#{global_config_file}): #{@global_config[key].inspect}" 58 | end 59 | 60 | return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? 61 | locations 62 | end 63 | 64 | def without=(array) 65 | unless array.empty? 66 | self[:without] = array.join(":") 67 | end 68 | end 69 | 70 | def without 71 | self[:without] ? self[:without].split(":").map { |w| w.to_sym } : [] 72 | end 73 | 74 | # @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"] 75 | def path 76 | path = ENV[key_for(:path)] || @global_config[key_for(:path)] 77 | return path if path && !@local_config.key?(key_for(:path)) 78 | 79 | if path = self[:path] 80 | "#{path}/#{Bundler.ruby_scope}" 81 | else 82 | Gem.dir 83 | end 84 | end 85 | 86 | def allow_sudo? 87 | !@local_config.key?(key_for(:path)) 88 | end 89 | 90 | private 91 | def key_for(key) 92 | key = key.to_s.sub(".", "__").upcase 93 | "BUNDLE_#{key}" 94 | end 95 | 96 | def set_key(key, value, hash, file) 97 | key = key_for(key) 98 | 99 | unless hash[key] == value 100 | hash[key] = value 101 | hash.delete(key) if value.nil? 102 | FileUtils.mkdir_p(file.dirname) 103 | File.open(file, "w") { |f| f.puts hash.to_yaml } 104 | end 105 | value 106 | end 107 | 108 | def global_config_file 109 | file = ENV["BUNDLE_CONFIG"] || File.join(Gem.user_home, ".bundle/config") 110 | Pathname.new(file) 111 | end 112 | 113 | def local_config_file 114 | Pathname.new("#{@root}/config") 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/bundler/lockfile_parser.rb: -------------------------------------------------------------------------------- 1 | require "strscan" 2 | 3 | module Bundler 4 | class LockfileParser 5 | attr_reader :sources, :dependencies, :specs, :platforms 6 | 7 | def initialize(lockfile) 8 | @platforms = [] 9 | @sources = [] 10 | @dependencies = [] 11 | @specs = [] 12 | @state = :source 13 | 14 | lockfile.split(/(\r?\n)+/).each do |line| 15 | if line == "DEPENDENCIES" 16 | @state = :dependency 17 | elsif line == "PLATFORMS" 18 | @state = :platform 19 | else 20 | send("parse_#{@state}", line) 21 | end 22 | end 23 | end 24 | 25 | private 26 | 27 | TYPES = { 28 | "GIT" => Bundler::Source::Git, 29 | "GEM" => Bundler::Source::Rubygems, 30 | "PATH" => Bundler::Source::Path 31 | } 32 | 33 | def parse_source(line) 34 | case line 35 | when "GIT", "GEM", "PATH" 36 | @current_source = nil 37 | @opts, @type = {}, line 38 | when " specs:" 39 | @current_source = TYPES[@type].from_lock(@opts) 40 | @sources << @current_source 41 | when /^ ([a-z]+): (.*)$/i 42 | value = $2 43 | value = true if value == "true" 44 | value = false if value == "false" 45 | 46 | key = $1 47 | 48 | if @opts[key] 49 | @opts[key] = Array(@opts[key]) 50 | @opts[key] << value 51 | else 52 | @opts[key] = value 53 | end 54 | else 55 | parse_spec(line) 56 | end 57 | end 58 | 59 | NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?' 60 | 61 | def parse_dependency(line) 62 | if line =~ %r{^ {2}#{NAME_VERSION}(!)?$} 63 | name, version, pinned = $1, $2, $4 64 | version = version.split(",").map { |d| d.strip } if version 65 | 66 | dep = Bundler::Dependency.new(name, version) 67 | 68 | if pinned && dep.name != 'bundler' 69 | spec = @specs.find { |s| s.name == dep.name } 70 | dep.source = spec.source if spec 71 | 72 | # Path sources need to know what the default name / version 73 | # to use in the case that there are no gemspecs present. A fake 74 | # gemspec is created based on the version set on the dependency 75 | # TODO: Use the version from the spec instead of from the dependency 76 | if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) 77 | dep.source.name = name 78 | dep.source.version = $1 79 | end 80 | end 81 | 82 | @dependencies << dep 83 | end 84 | end 85 | 86 | def parse_spec(line) 87 | if line =~ %r{^ {4}#{NAME_VERSION}$} 88 | name, version = $1, Gem::Version.new($2) 89 | platform = $3 ? Gem::Platform.new($3) : Gem::Platform::RUBY 90 | @current_spec = LazySpecification.new(name, version, platform) 91 | @current_spec.source = @current_source 92 | @specs << @current_spec 93 | elsif line =~ %r{^ {6}#{NAME_VERSION}$} 94 | name, version = $1, $2 95 | version = version.split(',').map { |d| d.strip } if version 96 | dep = Gem::Dependency.new(name, version) 97 | @current_spec.dependencies << dep 98 | end 99 | end 100 | 101 | def parse_platform(line) 102 | if line =~ /^ (.*)$/ 103 | @platforms << Gem::Platform.new($1) 104 | end 105 | end 106 | 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/bundler/spec_set.rb: -------------------------------------------------------------------------------- 1 | require 'tsort' 2 | 3 | module Bundler 4 | class SpecSet 5 | include TSort, Enumerable 6 | 7 | def initialize(specs) 8 | @specs = specs.sort_by { |s| s.name } 9 | end 10 | 11 | def each 12 | sorted.each { |s| yield s } 13 | end 14 | 15 | def length 16 | @specs.length 17 | end 18 | 19 | def for(dependencies, skip = [], check = false, match_current_platform = false) 20 | handled, deps, specs = {}, dependencies.dup, [] 21 | skip << 'bundler' 22 | 23 | until deps.empty? 24 | dep = deps.shift 25 | next if handled[dep] || skip.include?(dep.name) 26 | 27 | spec = lookup[dep.name].find do |s| 28 | match_current_platform ? 29 | Gem::Platform.match(s.platform) : 30 | s.match_platform(dep.__platform) 31 | end 32 | 33 | handled[dep] = true 34 | 35 | if spec 36 | specs << spec 37 | 38 | spec.dependencies.each do |d| 39 | next if d.type == :development 40 | d = DepProxy.new(d, dep.__platform) unless match_current_platform 41 | deps << d 42 | end 43 | elsif check 44 | return false 45 | end 46 | end 47 | 48 | if spec = lookup['bundler'].first 49 | specs << spec 50 | end 51 | 52 | check ? true : SpecSet.new(specs) 53 | end 54 | 55 | def valid_for?(deps) 56 | self.for(deps, [], true) 57 | end 58 | 59 | def [](key) 60 | key = key.name if key.respond_to?(:name) 61 | lookup[key].reverse 62 | end 63 | 64 | def []=(key, value) 65 | @specs << value 66 | @lookup = nil 67 | @sorted = nil 68 | value 69 | end 70 | 71 | def to_a 72 | sorted.dup 73 | end 74 | 75 | def to_hash 76 | lookup.dup 77 | end 78 | 79 | def materialize(deps, missing_specs = nil) 80 | materialized = self.for(deps, [], false, true).to_a 81 | materialized.map! do |s| 82 | next s unless s.is_a?(LazySpecification) 83 | spec = s.__materialize__ 84 | if missing_specs 85 | missing_specs << s unless spec 86 | else 87 | raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec 88 | end 89 | spec if spec 90 | end 91 | SpecSet.new(materialized.compact) 92 | end 93 | 94 | def merge(set) 95 | arr = sorted.dup 96 | set.each do |s| 97 | next if arr.any? { |s2| s2.name == s.name && s2.version == s.version && s2.platform == s.platform } 98 | arr << s 99 | end 100 | SpecSet.new(arr) 101 | end 102 | 103 | private 104 | 105 | def sorted 106 | rake = @specs.find { |s| s.name == 'rake' } 107 | @sorted ||= ([rake] + tsort).compact.uniq 108 | end 109 | 110 | def lookup 111 | @lookup ||= begin 112 | lookup = Hash.new { |h,k| h[k] = [] } 113 | specs = @specs.sort_by do |s| 114 | s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s 115 | end 116 | specs.reverse_each do |s| 117 | lookup[s.name] << s 118 | end 119 | lookup 120 | end 121 | end 122 | 123 | def tsort_each_node 124 | @specs.each { |s| yield s } 125 | end 126 | 127 | def tsort_each_child(s) 128 | s.dependencies.sort_by { |d| d.name }.each do |d| 129 | next if d.type == :development 130 | lookup[d.name].each { |s2| yield s2 } 131 | end 132 | end 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/actions/inject_into_file.rb: -------------------------------------------------------------------------------- 1 | require 'thor/actions/empty_directory' 2 | 3 | class Thor 4 | module Actions 5 | 6 | # Injects the given content into a file. Different from gsub_file, this 7 | # method is reversible. 8 | # 9 | # ==== Parameters 10 | # destination:: Relative path to the destination root 11 | # data:: Data to add to the file. Can be given as a block. 12 | # config:: give :verbose => false to not log the status and the flag 13 | # for injection (:after or :before) or :force => true for 14 | # insert two or more times the same content. 15 | # 16 | # ==== Examples 17 | # 18 | # inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" 19 | # 20 | # inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do 21 | # gems = ask "Which gems would you like to add?" 22 | # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") 23 | # end 24 | # 25 | def inject_into_file(destination, *args, &block) 26 | if block_given? 27 | data, config = block, args.shift 28 | else 29 | data, config = args.shift, args.shift 30 | end 31 | action InjectIntoFile.new(self, destination, data, config) 32 | end 33 | 34 | class InjectIntoFile < EmptyDirectory #:nodoc: 35 | attr_reader :replacement, :flag, :behavior 36 | 37 | def initialize(base, destination, data, config) 38 | super(base, destination, { :verbose => true }.merge(config)) 39 | 40 | @behavior, @flag = if @config.key?(:after) 41 | [:after, @config.delete(:after)] 42 | else 43 | [:before, @config.delete(:before)] 44 | end 45 | 46 | @replacement = data.is_a?(Proc) ? data.call : data 47 | @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp) 48 | end 49 | 50 | def invoke! 51 | say_status :invoke 52 | 53 | content = if @behavior == :after 54 | '\0' + replacement 55 | else 56 | replacement + '\0' 57 | end 58 | 59 | replace!(/#{flag}/, content, config[:force]) 60 | end 61 | 62 | def revoke! 63 | say_status :revoke 64 | 65 | regexp = if @behavior == :after 66 | content = '\1\2' 67 | /(#{flag})(.*)(#{Regexp.escape(replacement)})/m 68 | else 69 | content = '\2\3' 70 | /(#{Regexp.escape(replacement)})(.*)(#{flag})/m 71 | end 72 | 73 | replace!(regexp, content, true) 74 | end 75 | 76 | protected 77 | 78 | def say_status(behavior) 79 | status = if flag == /\A/ 80 | behavior == :invoke ? :prepend : :unprepend 81 | elsif flag == /\z/ 82 | behavior == :invoke ? :append : :unappend 83 | else 84 | behavior == :invoke ? :inject : :deinject 85 | end 86 | 87 | super(status, config[:verbose]) 88 | end 89 | 90 | # Adds the content to the file. 91 | # 92 | def replace!(regexp, string, force) 93 | unless base.options[:pretend] 94 | content = File.binread(destination) 95 | if force || !content.include?(replacement) 96 | content.gsub!(regexp, string) 97 | File.open(destination, 'wb') { |file| file.write(content) } 98 | end 99 | end 100 | end 101 | 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/actions/create_file.rb: -------------------------------------------------------------------------------- 1 | require 'thor/actions/empty_directory' 2 | 3 | class Thor 4 | module Actions 5 | 6 | # Create a new file relative to the destination root with the given data, 7 | # which is the return value of a block or a data string. 8 | # 9 | # ==== Parameters 10 | # destination:: the relative path to the destination root. 11 | # data:: the data to append to the file. 12 | # config:: give :verbose => false to not log the status. 13 | # 14 | # ==== Examples 15 | # 16 | # create_file "lib/fun_party.rb" do 17 | # hostname = ask("What is the virtual hostname I should use?") 18 | # "vhost.name = #{hostname}" 19 | # end 20 | # 21 | # create_file "config/apach.conf", "your apache config" 22 | # 23 | def create_file(destination, *args, &block) 24 | config = args.last.is_a?(Hash) ? args.pop : {} 25 | data = args.first 26 | action CreateFile.new(self, destination, block || data.to_s, config) 27 | end 28 | alias :add_file :create_file 29 | 30 | # AddFile is a subset of Template, which instead of rendering a file with 31 | # ERB, it gets the content from the user. 32 | # 33 | class CreateFile < EmptyDirectory #:nodoc: 34 | attr_reader :data 35 | 36 | def initialize(base, destination, data, config={}) 37 | @data = data 38 | super(base, destination, config) 39 | end 40 | 41 | # Checks if the content of the file at the destination is identical to the rendered result. 42 | # 43 | # ==== Returns 44 | # Boolean:: true if it is identical, false otherwise. 45 | # 46 | def identical? 47 | exists? && File.binread(destination) == render 48 | end 49 | 50 | # Holds the content to be added to the file. 51 | # 52 | def render 53 | @render ||= if data.is_a?(Proc) 54 | data.call 55 | else 56 | data 57 | end 58 | end 59 | 60 | def invoke! 61 | invoke_with_conflict_check do 62 | FileUtils.mkdir_p(File.dirname(destination)) 63 | File.open(destination, 'wb') { |f| f.write render } 64 | end 65 | given_destination 66 | end 67 | 68 | protected 69 | 70 | # Now on conflict we check if the file is identical or not. 71 | # 72 | def on_conflict_behavior(&block) 73 | if identical? 74 | say_status :identical, :blue 75 | else 76 | options = base.options.merge(config) 77 | force_or_skip_or_conflict(options[:force], options[:skip], &block) 78 | end 79 | end 80 | 81 | # If force is true, run the action, otherwise check if it's not being 82 | # skipped. If both are false, show the file_collision menu, if the menu 83 | # returns true, force it, otherwise skip. 84 | # 85 | def force_or_skip_or_conflict(force, skip, &block) 86 | if force 87 | say_status :force, :yellow 88 | block.call unless pretend? 89 | elsif skip 90 | say_status :skip, :yellow 91 | else 92 | say_status :conflict, :red 93 | force_or_skip_or_conflict(force_on_collision?, true, &block) 94 | end 95 | end 96 | 97 | # Shows the file collision menu to the user and gets the result. 98 | # 99 | def force_on_collision? 100 | base.shell.file_collision(destination){ render } 101 | end 102 | 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /lib/bundler/index.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class Index 3 | include Enumerable 4 | 5 | def self.build 6 | i = new 7 | yield i 8 | i 9 | end 10 | 11 | attr_reader :specs 12 | protected :specs 13 | 14 | def initialize 15 | @cache = {} 16 | @specs = Hash.new { |h,k| h[k] = [] } 17 | end 18 | 19 | def initialize_copy(o) 20 | super 21 | @cache = {} 22 | @specs = Hash.new { |h,k| h[k] = [] } 23 | 24 | o.specs.each do |name, array| 25 | @specs[name] = array.dup 26 | end 27 | end 28 | 29 | def empty? 30 | each { return false } 31 | true 32 | end 33 | 34 | def search(query) 35 | case query 36 | when Gem::Specification, RemoteSpecification, LazySpecification then search_by_spec(query) 37 | when String then @specs[query] 38 | else search_by_dependency(query) 39 | end 40 | end 41 | 42 | def search_for_all_platforms(dependency, base = []) 43 | specs = @specs[dependency.name] + base 44 | 45 | wants_prerelease = dependency.requirement.prerelease? 46 | only_prerelease = specs.all? {|spec| spec.version.prerelease? } 47 | found = specs.select { |spec| dependency.matches_spec?(spec) } 48 | 49 | unless wants_prerelease || only_prerelease 50 | found.reject! { |spec| spec.version.prerelease? } 51 | end 52 | 53 | found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] } 54 | end 55 | 56 | def sources 57 | @specs.values.map do |specs| 58 | specs.map{|s| s.source.class } 59 | end.flatten.uniq 60 | end 61 | 62 | alias [] search 63 | 64 | def <<(spec) 65 | arr = @specs[spec.name] 66 | 67 | arr.delete_if do |s| 68 | same_version?(s.version, spec.version) && s.platform == spec.platform 69 | end 70 | 71 | arr << spec 72 | spec 73 | end 74 | 75 | def each(&blk) 76 | @specs.values.each do |specs| 77 | specs.each(&blk) 78 | end 79 | end 80 | 81 | def use(other) 82 | return unless other 83 | other.each do |s| 84 | next if search_by_spec(s).any? 85 | @specs[s.name] << s 86 | end 87 | self 88 | end 89 | 90 | def ==(o) 91 | all? do |s| 92 | s2 = o[s].first and (s.dependencies & s2.dependencies).empty? 93 | end 94 | end 95 | 96 | private 97 | 98 | def search_by_spec(spec) 99 | @specs[spec.name].select do |s| 100 | same_version?(s.version, spec.version) && Gem::Platform.new(s.platform) == Gem::Platform.new(spec.platform) 101 | end 102 | end 103 | 104 | def same_version?(a, b) 105 | regex = /^(.*?)(?:\.0)*$/ 106 | 107 | ret = a.to_s[regex, 1] == b.to_s[regex, 1] 108 | end 109 | 110 | def spec_satisfies_dependency?(spec, dep) 111 | return false unless dep.name === spec.name 112 | dep.requirement.satisfied_by?(spec.version) 113 | end 114 | 115 | def search_by_dependency(dependency) 116 | @cache[dependency.hash] ||= begin 117 | specs = @specs[dependency.name] 118 | 119 | wants_prerelease = dependency.requirement.prerelease? 120 | only_prerelease = specs.all? {|spec| spec.version.prerelease? } 121 | found = specs.select { |spec| dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) } 122 | 123 | unless wants_prerelease || only_prerelease 124 | found.reject! { |spec| spec.version.prerelease? } 125 | end 126 | 127 | found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] } 128 | end 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/parser/option.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | class Option < Argument #:nodoc: 3 | attr_reader :aliases, :group, :lazy_default 4 | 5 | VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] 6 | 7 | def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil) 8 | super(name, description, required, type, default, banner) 9 | @lazy_default = lazy_default 10 | @group = group.to_s.capitalize if group 11 | @aliases = [*aliases].compact 12 | end 13 | 14 | # This parse quick options given as method_options. It makes several 15 | # assumptions, but you can be more specific using the option method. 16 | # 17 | # parse :foo => "bar" 18 | # #=> Option foo with default value bar 19 | # 20 | # parse [:foo, :baz] => "bar" 21 | # #=> Option foo with default value bar and alias :baz 22 | # 23 | # parse :foo => :required 24 | # #=> Required option foo without default value 25 | # 26 | # parse :foo => 2 27 | # #=> Option foo with default value 2 and type numeric 28 | # 29 | # parse :foo => :numeric 30 | # #=> Option foo without default value and type numeric 31 | # 32 | # parse :foo => true 33 | # #=> Option foo with default value true and type boolean 34 | # 35 | # The valid types are :boolean, :numeric, :hash, :array and :string. If none 36 | # is given a default type is assumed. This default type accepts arguments as 37 | # string (--foo=value) or booleans (just --foo). 38 | # 39 | # By default all options are optional, unless :required is given. 40 | # 41 | def self.parse(key, value) 42 | if key.is_a?(Array) 43 | name, *aliases = key 44 | else 45 | name, aliases = key, [] 46 | end 47 | 48 | name = name.to_s 49 | default = value 50 | 51 | type = case value 52 | when Symbol 53 | default = nil 54 | if VALID_TYPES.include?(value) 55 | value 56 | elsif required = (value == :required) 57 | :string 58 | end 59 | when TrueClass, FalseClass 60 | :boolean 61 | when Numeric 62 | :numeric 63 | when Hash, Array, String 64 | value.class.name.downcase.to_sym 65 | end 66 | 67 | self.new(name.to_s, nil, required, type, default, nil, nil, nil, aliases) 68 | end 69 | 70 | def switch_name 71 | @switch_name ||= dasherized? ? name : dasherize(name) 72 | end 73 | 74 | def human_name 75 | @human_name ||= dasherized? ? undasherize(name) : name 76 | end 77 | 78 | def usage(padding=0) 79 | sample = if banner && !banner.to_s.empty? 80 | "#{switch_name}=#{banner}" 81 | else 82 | switch_name 83 | end 84 | 85 | sample = "[#{sample}]" unless required? 86 | 87 | if aliases.empty? 88 | (" " * padding) << sample 89 | else 90 | "#{aliases.join(', ')}, #{sample}" 91 | end 92 | end 93 | 94 | VALID_TYPES.each do |type| 95 | class_eval <<-RUBY, __FILE__, __LINE__ + 1 96 | def #{type}? 97 | self.type == #{type.inspect} 98 | end 99 | RUBY 100 | end 101 | 102 | protected 103 | 104 | def validate! 105 | raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? 106 | end 107 | 108 | def dasherized? 109 | name.index('-') == 0 110 | end 111 | 112 | def undasherize(str) 113 | str.sub(/^-{1,2}/, '') 114 | end 115 | 116 | def dasherize(str) 117 | (str.length > 1 ? "--" : "-") + str.gsub('_', '-') 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /spec/support/indexes.rb: -------------------------------------------------------------------------------- 1 | module Spec 2 | module Indexes 3 | def dep(name, reqs = nil) 4 | @deps ||= [] 5 | @deps << Bundler::Dependency.new(name, :version => reqs) 6 | end 7 | 8 | def platform(*args) 9 | @platforms ||= [] 10 | @platforms.concat args.map { |p| Gem::Platform.new(p) } 11 | end 12 | 13 | alias platforms platform 14 | 15 | def resolve 16 | @platforms ||= ['ruby'] 17 | deps = [] 18 | @deps.each do |d| 19 | @platforms.each do |p| 20 | deps << Bundler::DepProxy.new(d, p) 21 | end 22 | end 23 | Bundler::Resolver.resolve(deps, @index) 24 | end 25 | 26 | def should_resolve_as(specs) 27 | got = resolve 28 | got = got.map { |s| s.full_name }.sort 29 | got.should == specs.sort 30 | end 31 | 32 | def should_conflict_on(names) 33 | begin 34 | got = resolve 35 | flunk "The resolve succeeded with: #{got.map { |s| s.full_name }.sort.inspect}" 36 | rescue Bundler::VersionConflict => e 37 | Array(names).sort.should == e.conflicts.sort 38 | end 39 | end 40 | 41 | def gem(*args, &blk) 42 | build_spec(*args, &blk).first 43 | end 44 | 45 | def an_awesome_index 46 | build_index do 47 | gem "rack", %w(0.8 0.9 0.9.1 0.9.2 1.0 1.1) 48 | gem "rack-mount", %w(0.4 0.5 0.5.1 0.5.2 0.6) 49 | 50 | # --- Rails 51 | versions "1.2.3 2.2.3 2.3.5 3.0.0.beta 3.0.0.beta1" do |version| 52 | gem "activesupport", version 53 | gem "actionpack", version do 54 | dep "activesupport", version 55 | if version >= v('3.0.0.beta') 56 | dep "rack", '~> 1.1' 57 | dep "rack-mount", ">= 0.5" 58 | elsif version > v('2.3') then dep "rack", '~> 1.0.0' 59 | elsif version > v('2.0.0') then dep "rack", '~> 0.9.0' 60 | end 61 | end 62 | gem "activerecord", version do 63 | dep "activesupport", version 64 | dep "arel", ">= 0.2" if version >= v('3.0.0.beta') 65 | end 66 | gem "actionmailer", version do 67 | dep "activesupport", version 68 | dep "actionmailer", version 69 | end 70 | if version < v('3.0.0.beta') 71 | gem "railties", version do 72 | dep "activerecord", version 73 | dep "actionpack", version 74 | dep "actionmailer", version 75 | dep "activesupport", version 76 | end 77 | else 78 | gem "railties", version 79 | gem "rails", version do 80 | dep "activerecord", version 81 | dep "actionpack", version 82 | dep "actionmailer", version 83 | dep "activesupport", version 84 | dep "railties", version 85 | end 86 | end 87 | end 88 | 89 | versions '1.0 1.2 1.2.1 1.2.2 1.3 1.3.0.1 1.3.5 1.4.0 1.4.2 1.4.2.1' do |version| 90 | platforms "ruby java mswin32 mingw32" do |platform| 91 | next if version == v('1.4.2.1') && platform != pl('x86-mswin32') 92 | next if version == v('1.4.2') && platform == pl('x86-mswin32') 93 | gem "nokogiri", version, platform do 94 | dep "weakling", ">= 0.0.3" if platform =~ pl('java') 95 | end 96 | end 97 | end 98 | 99 | versions '0.0.1 0.0.2 0.0.3' do |version| 100 | gem "weakling", version 101 | end 102 | 103 | # --- Rails related 104 | versions '1.2.3 2.2.3 2.3.5' do |version| 105 | gem "activemerchant", version do 106 | dep "activesupport", ">= #{version}" 107 | end 108 | end 109 | end 110 | end 111 | end 112 | end -------------------------------------------------------------------------------- /lib/bundler/graph.rb: -------------------------------------------------------------------------------- 1 | module Bundler 2 | class Graph 3 | 4 | USER_OPTIONS = {:style => 'filled', :fillcolor => '#B9B9D5'}.freeze 5 | 6 | def initialize(env) 7 | @env = env 8 | end 9 | 10 | def nodes 11 | populate 12 | @nodes 13 | end 14 | 15 | def groups 16 | populate 17 | @groups 18 | end 19 | 20 | def viz(output_file, show_gem_versions = false, show_dependency_requirements = false) 21 | require 'graphviz' 22 | populate 23 | 24 | graph_viz = GraphViz::new('Gemfile', {:concentrate => true, :normalize => true, :nodesep => 0.55}) 25 | graph_viz.edge[:fontname] = graph_viz.node[:fontname] = 'Arial, Helvetica, SansSerif' 26 | graph_viz.edge[:fontsize] = 12 27 | 28 | viz_nodes = {} 29 | 30 | # populate all of the nodes 31 | nodes.each do |name, node| 32 | label = name.dup 33 | label << "\n#{node.version}" if show_gem_versions 34 | options = { :label => label } 35 | options.merge!( USER_OPTIONS ) if node.is_user 36 | viz_nodes[name] = graph_viz.add_node( name, options ) 37 | end 38 | 39 | group_nodes = {} 40 | @groups.each do |name, dependencies| 41 | group_nodes[name] = graph_viz.add_node(name.to_s, { :shape => 'box3d', :fontsize => 16 }.merge(USER_OPTIONS)) 42 | dependencies.each do |dependency| 43 | options = { :weight => 2 } 44 | if show_dependency_requirements && (dependency.requirement.to_s != ">= 0") 45 | options[:label] = dependency.requirement.to_s 46 | end 47 | graph_viz.add_edge( group_nodes[name], viz_nodes[dependency.name], options ) 48 | end 49 | end 50 | 51 | @groups.keys.select { |group| group != :default }.each do |group| 52 | graph_viz.add_edge( group_nodes[group], group_nodes[:default], { :weight => 2 } ) 53 | end 54 | 55 | viz_nodes.each do |name, node| 56 | nodes[name].dependencies.each do |dependency| 57 | options = { } 58 | if nodes[dependency.name].is_user 59 | options[:constraint] = false 60 | end 61 | if show_dependency_requirements && (dependency.requirement.to_s != ">= 0") 62 | options[:label] = dependency.requirement.to_s 63 | end 64 | 65 | graph_viz.add_edge( node, viz_nodes[dependency.name], options ) 66 | end 67 | end 68 | 69 | graph_viz.output( :png => output_file ) 70 | end 71 | 72 | private 73 | 74 | def populate 75 | return if @populated 76 | 77 | # hash of name => GraphNode 78 | @nodes = {} 79 | @groups = {} 80 | 81 | # Populate @nodes 82 | @env.specs.each { |spec| @nodes[spec.name] = GraphNode.new(spec.name, spec.version) } 83 | 84 | # For gems in Gemfile, add details 85 | @env.current_dependencies.each do |dependency| 86 | next unless node = @nodes[dependency.name] 87 | node.is_user = true 88 | 89 | dependency.groups.each do |group| 90 | if @groups.has_key? group 91 | group = @groups[group] 92 | else 93 | group = @groups[group] = [] 94 | end 95 | group << dependency 96 | end 97 | end 98 | 99 | # walk though a final time and add edges 100 | @env.specs.each do |spec| 101 | 102 | from = @nodes[spec.name] 103 | spec.runtime_dependencies.each do |dependency| 104 | from.dependencies << dependency 105 | end 106 | 107 | end 108 | 109 | @nodes.freeze 110 | @groups.freeze 111 | @populated = true 112 | end 113 | 114 | end 115 | 116 | # Add version info 117 | class GraphNode 118 | 119 | def initialize(name, version) 120 | @name = name 121 | @version = version 122 | @is_user = false 123 | @dependencies = [] 124 | end 125 | 126 | attr_reader :name, :dependencies, :version 127 | attr_accessor :is_user 128 | 129 | end 130 | end 131 | -------------------------------------------------------------------------------- /man/bundle-config.ronn: -------------------------------------------------------------------------------- 1 | bundle-config(1) -- Set bundler configuration options 2 | ===================================================== 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle config` [ []] 7 | 8 | ## DESCRIPTION 9 | 10 | This command allows you to interact with bundler's configuration system. 11 | Bundler retrieves its configuration from the local application (`app/.bundle/config`), 12 | environment variables, and the user's home directory (`~/.bundle/config`), 13 | in that order of priority. 14 | 15 | Executing `bundle config` with no parameters will print a list of all 16 | bundler configuration for the current bundle, and where that configuration 17 | was set. 18 | 19 | Executing `bundle config ` will print the value of that configuration 20 | setting, and where it was set. 21 | 22 | Executing `bundle config ` will set that configuration to the 23 | value specified for all bundles executed as the current user. The configuration 24 | will be stored in `~/.bundle/config`. 25 | 26 | ## BUILD OPTIONS 27 | 28 | You can use `bundle config` to give bundler the flags to pass to the gem 29 | installer every time bundler tries to install a particular gem. 30 | 31 | A very common example, the `mysql` gem, requires Snow Leopard users to 32 | pass configuration flags to `gem install` to specify where to find the 33 | `mysql_config` executable. 34 | 35 | gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config 36 | 37 | Since the specific location of that executable can change from machine 38 | to machine, you can specify these flags on a per-machine basis. 39 | 40 | bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config 41 | 42 | After running this command, every time bundler needs to install the 43 | `mysql` gem, it will pass along the flags you specified. 44 | 45 | ## CONFIGURATION KEYS 46 | 47 | Configuration keys in bundler have two forms: the canonical form and the 48 | environment variable form. 49 | 50 | For instance, passing the `--without` flag to [bundle install(1)][bundle-install] 51 | prevents Bundler from installing certain groups specified in the Gemfile(5). Bundler 52 | persists this value in `app/.bundle/config` so that calls to `Bundler.setup` 53 | do not try to find gems from the `Gemfile` that you didn't install. Additionally, 54 | subsequent calls to [bundle install(1)][bundle-install] remember this setting and skip those 55 | groups. 56 | 57 | The canonical form of this configuration is `"without"`. To convert the canonical 58 | form to the environment variable form, capitalize it, and prepend `BUNDLE_`. The 59 | environment variable form of `"without"` is `BUNDLE_WITHOUT`. 60 | 61 | ## LIST OF AVAILABLE KEYS 62 | 63 | The following is a list of all configuration keys and their purpose. You can 64 | learn more about their operation in [bundle install(1)][bundle-install]. 65 | 66 | * `path` (`BUNDLE_PATH`): 67 | The location on disk to install gems. Defaults to `$GEM_HOME` in development 68 | and `vendor/bundler` when `--deployment` is used 69 | * `frozen` (`BUNDLE_FROZEN`): 70 | Disallow changes to the `Gemfile`. Defaults to `true` when `--deployment` 71 | is used. 72 | * `without` (`BUNDLE_WITHOUT`): 73 | A `:`-separated list of groups whose gems bundler should not install 74 | * `bin` (`BUNDLE_BIN`): 75 | Install executables from gems in the bundle to the specified directory. 76 | Defaults to `false`. 77 | * `gemfile` (`BUNDLE_GEMFILE`): 78 | The name of the file that bundler should use as the `Gemfile`. This location 79 | of this file also sets the root of the project, which is used to resolve 80 | relative paths in the `Gemfile`, among other things. By default, bundler 81 | will search up from the current working directory until it finds a 82 | `Gemfile`. 83 | 84 | In general, you should set these settings per-application by using the applicable 85 | flag to the [bundle install(1)][bundle-install] command. 86 | 87 | You can set them globally either via environment variables or `bundle config`, 88 | whichever is preferable for your setup. If you use both, environment variables 89 | will take preference over global settings. 90 | 91 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/task.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | class Task < Struct.new(:name, :description, :long_description, :usage, :options) 3 | FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ 4 | 5 | def initialize(name, description, long_description, usage, options=nil) 6 | super(name.to_s, description, long_description, usage, options || {}) 7 | end 8 | 9 | def initialize_copy(other) #:nodoc: 10 | super(other) 11 | self.options = other.options.dup if other.options 12 | end 13 | 14 | def hidden? 15 | false 16 | end 17 | 18 | # By default, a task invokes a method in the thor class. You can change this 19 | # implementation to create custom tasks. 20 | def run(instance, args=[]) 21 | public_method?(instance) ? 22 | instance.send(name, *args) : instance.class.handle_no_task_error(name) 23 | rescue ArgumentError => e 24 | handle_argument_error?(instance, e, caller) ? 25 | instance.class.handle_argument_error(self, e) : (raise e) 26 | rescue NoMethodError => e 27 | handle_no_method_error?(instance, e, caller) ? 28 | instance.class.handle_no_task_error(name) : (raise e) 29 | end 30 | 31 | # Returns the formatted usage by injecting given required arguments 32 | # and required options into the given usage. 33 | def formatted_usage(klass, namespace = true, subcommand = false) 34 | if namespace 35 | namespace = klass.namespace 36 | formatted = "#{namespace.gsub(/^(default)/,'')}:" 37 | formatted.sub!(/.$/, ' ') if subcommand 38 | end 39 | 40 | formatted ||= "" 41 | 42 | # Add usage with required arguments 43 | formatted << if klass && !klass.arguments.empty? 44 | usage.to_s.gsub(/^#{name}/) do |match| 45 | match << " " << klass.arguments.map{ |a| a.usage }.compact.join(' ') 46 | end 47 | else 48 | usage.to_s 49 | end 50 | 51 | # Add required options 52 | formatted << " #{required_options}" 53 | 54 | # Strip and go! 55 | formatted.strip 56 | end 57 | 58 | protected 59 | 60 | def not_debugging?(instance) 61 | !(instance.class.respond_to?(:debugging) && instance.class.debugging) 62 | end 63 | 64 | def required_options 65 | @required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ") 66 | end 67 | 68 | # Given a target, checks if this class name is not a private/protected method. 69 | def public_method?(instance) #:nodoc: 70 | collection = instance.private_methods + instance.protected_methods 71 | (collection & [name.to_s, name.to_sym]).empty? 72 | end 73 | 74 | def sans_backtrace(backtrace, caller) #:nodoc: 75 | saned = backtrace.reject { |frame| frame =~ FILE_REGEXP } 76 | saned -= caller 77 | end 78 | 79 | def handle_argument_error?(instance, error, caller) 80 | not_debugging?(instance) && error.message =~ /wrong number of arguments/ && begin 81 | saned = sans_backtrace(error.backtrace, caller) 82 | # Ruby 1.9 always include the called method in the backtrace 83 | saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9") 84 | end 85 | end 86 | 87 | def handle_no_method_error?(instance, error, caller) 88 | not_debugging?(instance) && 89 | error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ 90 | end 91 | end 92 | 93 | # A task that is hidden in help messages but still invocable. 94 | class HiddenTask < Task 95 | def hidden? 96 | true 97 | end 98 | end 99 | 100 | # A dynamic task that handles method missing scenarios. 101 | class DynamicTask < Task 102 | def initialize(name, options=nil) 103 | super(name.to_s, "A dynamically-generated task", name.to_s, name.to_s, options) 104 | end 105 | 106 | def run(instance, args=[]) 107 | if (instance.methods & [name.to_s, name.to_sym]).empty? 108 | super 109 | else 110 | instance.class.handle_no_task_error(name) 111 | end 112 | end 113 | end 114 | end -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/shell/color.rb: -------------------------------------------------------------------------------- 1 | require 'thor/shell/basic' 2 | 3 | class Thor 4 | module Shell 5 | # Inherit from Thor::Shell::Basic and add set_color behavior. Check 6 | # Thor::Shell::Basic to see all available methods. 7 | # 8 | class Color < Basic 9 | # Embed in a String to clear all previous ANSI sequences. 10 | CLEAR = "\e[0m" 11 | # The start of an ANSI bold sequence. 12 | BOLD = "\e[1m" 13 | 14 | # Set the terminal's foreground ANSI color to black. 15 | BLACK = "\e[30m" 16 | # Set the terminal's foreground ANSI color to red. 17 | RED = "\e[31m" 18 | # Set the terminal's foreground ANSI color to green. 19 | GREEN = "\e[32m" 20 | # Set the terminal's foreground ANSI color to yellow. 21 | YELLOW = "\e[33m" 22 | # Set the terminal's foreground ANSI color to blue. 23 | BLUE = "\e[34m" 24 | # Set the terminal's foreground ANSI color to magenta. 25 | MAGENTA = "\e[35m" 26 | # Set the terminal's foreground ANSI color to cyan. 27 | CYAN = "\e[36m" 28 | # Set the terminal's foreground ANSI color to white. 29 | WHITE = "\e[37m" 30 | 31 | # Set the terminal's background ANSI color to black. 32 | ON_BLACK = "\e[40m" 33 | # Set the terminal's background ANSI color to red. 34 | ON_RED = "\e[41m" 35 | # Set the terminal's background ANSI color to green. 36 | ON_GREEN = "\e[42m" 37 | # Set the terminal's background ANSI color to yellow. 38 | ON_YELLOW = "\e[43m" 39 | # Set the terminal's background ANSI color to blue. 40 | ON_BLUE = "\e[44m" 41 | # Set the terminal's background ANSI color to magenta. 42 | ON_MAGENTA = "\e[45m" 43 | # Set the terminal's background ANSI color to cyan. 44 | ON_CYAN = "\e[46m" 45 | # Set the terminal's background ANSI color to white. 46 | ON_WHITE = "\e[47m" 47 | 48 | # Set color by using a string or one of the defined constants. If a third 49 | # option is set to true, it also adds bold to the string. This is based 50 | # on Highline implementation and it automatically appends CLEAR to the end 51 | # of the returned String. 52 | # 53 | def set_color(string, color, bold=false) 54 | color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) 55 | bold = bold ? BOLD : "" 56 | "#{bold}#{color}#{string}#{CLEAR}" 57 | end 58 | 59 | protected 60 | 61 | # Overwrite show_diff to show diff with colors if Diff::LCS is 62 | # available. 63 | # 64 | def show_diff(destination, content) #:nodoc: 65 | if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil? 66 | actual = File.binread(destination).to_s.split("\n") 67 | content = content.to_s.split("\n") 68 | 69 | Diff::LCS.sdiff(actual, content).each do |diff| 70 | output_diff_line(diff) 71 | end 72 | else 73 | super 74 | end 75 | end 76 | 77 | def output_diff_line(diff) #:nodoc: 78 | case diff.action 79 | when '-' 80 | say "- #{diff.old_element.chomp}", :red, true 81 | when '+' 82 | say "+ #{diff.new_element.chomp}", :green, true 83 | when '!' 84 | say "- #{diff.old_element.chomp}", :red, true 85 | say "+ #{diff.new_element.chomp}", :green, true 86 | else 87 | say " #{diff.old_element.chomp}", nil, true 88 | end 89 | end 90 | 91 | # Check if Diff::LCS is loaded. If it is, use it to create pretty output 92 | # for diff. 93 | # 94 | def diff_lcs_loaded? #:nodoc: 95 | return true if defined?(Diff::LCS) 96 | return @diff_lcs_loaded unless @diff_lcs_loaded.nil? 97 | 98 | @diff_lcs_loaded = begin 99 | require 'diff/lcs' 100 | true 101 | rescue LoadError 102 | false 103 | end 104 | end 105 | 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/parser/arguments.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | class Arguments #:nodoc: 3 | NUMERIC = /(\d*\.\d+|\d+)/ 4 | 5 | # Receives an array of args and returns two arrays, one with arguments 6 | # and one with switches. 7 | # 8 | def self.split(args) 9 | arguments = [] 10 | 11 | args.each do |item| 12 | break if item =~ /^-/ 13 | arguments << item 14 | end 15 | 16 | return arguments, args[Range.new(arguments.size, -1)] 17 | end 18 | 19 | def self.parse(*args) 20 | to_parse = args.pop 21 | new(*args).parse(to_parse) 22 | end 23 | 24 | # Takes an array of Thor::Argument objects. 25 | # 26 | def initialize(arguments=[]) 27 | @assigns, @non_assigned_required = {}, [] 28 | @switches = arguments 29 | 30 | arguments.each do |argument| 31 | if argument.default 32 | @assigns[argument.human_name] = argument.default 33 | elsif argument.required? 34 | @non_assigned_required << argument 35 | end 36 | end 37 | end 38 | 39 | def parse(args) 40 | @pile = args.dup 41 | 42 | @switches.each do |argument| 43 | break unless peek 44 | @non_assigned_required.delete(argument) 45 | @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) 46 | end 47 | 48 | check_requirement! 49 | @assigns 50 | end 51 | 52 | private 53 | 54 | def no_or_skip?(arg) 55 | arg =~ /^--(no|skip)-([-\w]+)$/ 56 | $2 57 | end 58 | 59 | def last? 60 | @pile.empty? 61 | end 62 | 63 | def peek 64 | @pile.first 65 | end 66 | 67 | def shift 68 | @pile.shift 69 | end 70 | 71 | def unshift(arg) 72 | unless arg.kind_of?(Array) 73 | @pile.unshift(arg) 74 | else 75 | @pile = arg + @pile 76 | end 77 | end 78 | 79 | def current_is_value? 80 | peek && peek.to_s !~ /^-/ 81 | end 82 | 83 | # Runs through the argument array getting strings that contains ":" and 84 | # mark it as a hash: 85 | # 86 | # [ "name:string", "age:integer" ] 87 | # 88 | # Becomes: 89 | # 90 | # { "name" => "string", "age" => "integer" } 91 | # 92 | def parse_hash(name) 93 | return shift if peek.is_a?(Hash) 94 | hash = {} 95 | 96 | while current_is_value? && peek.include?(?:) 97 | key, value = shift.split(':') 98 | hash[key] = value 99 | end 100 | hash 101 | end 102 | 103 | # Runs through the argument array getting all strings until no string is 104 | # found or a switch is found. 105 | # 106 | # ["a", "b", "c"] 107 | # 108 | # And returns it as an array: 109 | # 110 | # ["a", "b", "c"] 111 | # 112 | def parse_array(name) 113 | return shift if peek.is_a?(Array) 114 | array = [] 115 | 116 | while current_is_value? 117 | array << shift 118 | end 119 | array 120 | end 121 | 122 | # Check if the peek is numeric format and return a Float or Integer. 123 | # Otherwise raises an error. 124 | # 125 | def parse_numeric(name) 126 | return shift if peek.is_a?(Numeric) 127 | 128 | unless peek =~ NUMERIC && $& == peek 129 | raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" 130 | end 131 | 132 | $&.index('.') ? shift.to_f : shift.to_i 133 | end 134 | 135 | # Parse string: 136 | # for --string-arg, just return the current value in the pile 137 | # for --no-string-arg, nil 138 | # 139 | def parse_string(name) 140 | if no_or_skip?(name) 141 | nil 142 | else 143 | shift 144 | end 145 | end 146 | 147 | # Raises an error if @non_assigned_required array is not empty. 148 | # 149 | def check_requirement! 150 | unless @non_assigned_required.empty? 151 | names = @non_assigned_required.map do |o| 152 | o.respond_to?(:switch_name) ? o.switch_name : o.human_name 153 | end.join("', '") 154 | 155 | class_name = self.class.name.split('::').last.downcase 156 | raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" 157 | end 158 | end 159 | 160 | end 161 | end 162 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | ## Bundler 0.9 to 1.0 and above 2 | 3 | Upgrading from Bundler 0.9 to 1.0 is relatively painless. The 4 | Gemfile API is the same, so your old Gemfiles should continue 5 | to work. 6 | 7 | The "env" file that 0.9 created at `.bundle/environment.rb` has been 8 | removed. As a side effect of this, Passenger will only find your 9 | bundled gems if you install with `bundle install --deployment`. 10 | Alternatively, you can tell Passenger where you gems are installed, 11 | [something like this](http://bit.ly/passenger-gem-home). 12 | 13 | The `bundle lock` command is no longer needed, as the 14 | Gemfile.lock file is now automatically generated by `bundle install`. 15 | If you have not yet done so, add your Gemfile.lock to source control 16 | and check it in. 17 | 18 | Running `bundle install` no longer updates the versions of your gems. 19 | If you need to update just one gem, run `bundle update GEMNAME`. To 20 | update all gems to the newest versions possible, run `bundle update`. 21 | 22 | Bundler now supports multiple platforms, using a block syntax to 23 | declare platform-specific gems: 24 | 25 | platform :jruby do 26 | gem "jruby-maven-plugins" 27 | end 28 | 29 | Deploying using Bundler is even easier than it was before, as Bundler 30 | now includes a Capistrano recipe. Simply add this line to the top of 31 | your deploy.rb file to run Bundler automatically as part of deploying: 32 | 33 | require 'bundler/capistrano' 34 | 35 | For more details on deploying using bundler, see the documentation 36 | for the bundler cap task, and the [documentation on deploying](http://gembundler.com/v1.0/deploying.html). 37 | 38 | 39 | ## Bundler 0.8 to 0.9 and above 40 | 41 | Upgrading to Bundler 0.9 from Bundler 0.8 requires upgrading several 42 | API calls in your Gemfile, and some workarounds if you are using Rails 2.3. 43 | 44 | ### Gemfile Removals 45 | 46 | Bundler 0.9 removes the following Bundler 0.8 Gemfile APIs: 47 | 48 | 1. `disable_system_gems`: This is now the default (and only) option 49 | for bundler. Bundler uses the system gems you have specified 50 | in the Gemfile, and only the system gems you have specified 51 | (and their dependencies) 52 | 2. `disable_rubygems`: This is no longer supported. We are looking 53 | into ways to get the fastest performance out of each supported 54 | scenario, and we will make speed the default where possible. 55 | 3. `clear_sources`: Bundler now defaults to an empty source 56 | list. If you want to include Rubygems, you can add the source 57 | via source "http://gemcutter.org". If you use bundle init, this 58 | source will be automatically added for you in the generated 59 | Gemfile 60 | 4. `bundle_path`: You can specify this setting when installing 61 | via `bundle install /path/to/bundle`. Bundler will remember 62 | where you installed the dependencies to on a particular 63 | machine for future installs, loads, setups, etc. 64 | 5. `bin_path`: Bundler no longer generates binaries in the root 65 | of your app. You should use `bundle exec` to execute binaries 66 | in the current context. 67 | 68 | ### Gemfile Changes 69 | 70 | Bundler 0.9 changes the following Bundler 0.8 Gemfile APIs: 71 | 72 | 1. Bundler 0.8 supported :only and :except as APIs for describing 73 | groups of gems. Bundler 0.9 supports a single `group` method, 74 | which you can use to group gems together. See the above "Group" 75 | section for more information. 76 | 77 | This means that `gem "foo", :only => :production` becomes 78 | `gem "foo", :group => :production`, and 79 | `only :production { gem "foo" }` becomes 80 | `group :production { gem "foo" }` 81 | 82 | The short version is: group your gems together logically, and 83 | use the available commands to make use of the groups you've 84 | created. 85 | 86 | 2. `:require_as` becomes `:require` 87 | 88 | 3. `:vendored_at` is fully removed; you should use `:path` 89 | 90 | ### API Changes 91 | 92 | 1. `Bundler.require_env(:environment)` becomes 93 | `Bundler.require(:multiple, :groups)`. You must 94 | now specify the default group (the default group is the 95 | group made up of the gems not assigned to any group) 96 | explicitly. So `Bundler.require_env(:test)` becomes 97 | `Bundler.require(:default, :test)` 98 | 99 | 2. `require 'vendor/gems/environment'`: In unlocked 100 | mode, where using system gems, this becomes 101 | `Bundler.setup(:multiple, :groups)`. If you don't 102 | specify any groups, this puts all groups on the load 103 | path. In locked, mode, it becomes `require '.bundle/environment'` 104 | -------------------------------------------------------------------------------- /man/bundle-exec.ronn: -------------------------------------------------------------------------------- 1 | bundle-exec(1) -- Execute a command in the context of the bundle 2 | ================================================================ 3 | 4 | ## SYNOPSIS 5 | 6 | `bundle exec` 7 | 8 | ## DESCRIPTION 9 | 10 | This command executes the command, making all gems specified in the 11 | `Gemfile(5)` available to `require` in Ruby programs. 12 | 13 | Essentially, if you would normally have run something like 14 | `rspec spec/my_spec.rb`, and you want to use the gems specified 15 | in the `Gemfile(5)` and installed via [bundle install(1)][bundle-install], you 16 | should run `bundle exec rspec spec/my_spec.rb`. 17 | 18 | Note that `bundle exec` does not require that an executable is 19 | available on your shell's `$PATH`. 20 | 21 | ## BUNDLE INSTALL --BINSTUBS 22 | 23 | If you use the `--binstubs` flag in [bundle install(1)][bundle-install], Bundler will 24 | automatically create a directory (which defaults to `app_root/bin`) 25 | containing all of the executables available from gems in the bundle. 26 | 27 | After using `--binstubs`, `bin/rspec spec/my_spec.rb` is identical 28 | to `bundle exec rspec spec/my_spec.rb`. 29 | 30 | ## ENVIRONMENT MODIFICATIONS 31 | 32 | `bundle exec` makes a number of changes to the shell environment, 33 | then executes the command you specify in full. 34 | 35 | * make sure that it's still possible to shell out to `bundle` 36 | from inside a command invoked by `bundle exec` (using 37 | `$BUNDLE_BIN_PATH`) 38 | * put the directory containing executables (like `rails`, `rspec`, 39 | `rackup`) for your bundle on `$PATH` 40 | * make sure that if bundler is invoked in the subshell, it uses 41 | the same `Gemfile` (by setting `BUNDLE_GEMFILE`) 42 | * add `-rbundler/setup` to `$RUBYOPT`, which makes sure that 43 | Ruby programs invoked in the subshell can see the gems in 44 | the bundle 45 | 46 | It also modifies Rubygems: 47 | 48 | * disallow loading additional gems not in the bundle 49 | * modify the `gem` method to be a no-op if a gem matching 50 | the requirements is in the bundle, and to raise a 51 | `Gem::LoadError` if it's not 52 | * Define `Gem.refresh` to be a no-op, since the source 53 | index is always frozen when using bundler, and to 54 | prevent gems from the system leaking into the environment 55 | * Override `Gem.bin_path` to use the gems in the bundle, 56 | making system executables work 57 | * Add all gems in the bundle into Gem.loaded_specs 58 | 59 | ### Shelling out 60 | 61 | When shelling out (using the `system` or backticks methods, 62 | for example), Bundler's environment changes will propogate to 63 | the subshell environment. If you desire to shell out without 64 | Bundler's environment changes, simply employ the `with_clean_env` 65 | method. It will restore all environment variables to what they 66 | were before Bundler was activated. For example: 67 | 68 | Bundler.with_clean_env do 69 | `brew install wget` 70 | end 71 | 72 | ## RUBYGEMS PLUGINS 73 | 74 | At present, the Rubygems plugin system requires all files 75 | named `rubygems_plugin.rb` on the load path of _any_ installed 76 | gem when any Ruby code requires `rubygems.rb`. This includes 77 | executables installed into the system, like `rails`, `rackup`, 78 | and `rspec`. 79 | 80 | Since Rubygems plugins can contain arbitrary Ruby code, they 81 | commonly end up activating themselves or their dependencies. 82 | 83 | For instance, the `gemcutter 0.5` gem depended on `json_pure`. 84 | If you had that version of gemcutter installed (even if 85 | you _also_ had a newer version without this problem), Rubygems 86 | would activate `gemcutter 0.5` and `json_pure `. 87 | 88 | If your Gemfile(5) also contained `json_pure` (or a gem 89 | with a dependency on `json_pure`), the latest version on 90 | your system might conflict with the version in your 91 | Gemfile(5), or the snapshot version in your `Gemfile.lock`. 92 | 93 | If this happens, bundler will say: 94 | 95 | You have already activated json_pure 1.4.6 but your Gemfile 96 | requires json_pure 1.4.3. Consider using bundle exec. 97 | 98 | In this situation, you almost certainly want to remove the 99 | underlying gem with the problematic gem plugin. In general, 100 | the authors of these plugins (in this case, the `gemcutter` 101 | gem) have released newer versions that are more careful in 102 | their plugins. 103 | 104 | You can find a list of all the gems containing gem plugins 105 | by running 106 | 107 | ruby -rubygems -e "puts Gem.find_files('rubygems_plugin.rb')" 108 | 109 | At the very least, you should remove all but the newest 110 | version of each gem plugin, and also remove all gem plugins 111 | that you aren't using (`gem uninstall gem_name`). 112 | -------------------------------------------------------------------------------- /spec/other/gem_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require 'bundler/gem_helper' 3 | 4 | describe "Bundler::GemHelper tasks" do 5 | context "determining gemspec" do 6 | it "interpolates the name when there is only one gemspec" do 7 | bundle 'gem test' 8 | app = bundled_app("test") 9 | helper = Bundler::GemHelper.new(app.to_s) 10 | helper.gemspec.name.should == 'test' 11 | end 12 | 13 | it "should fail when there is no gemspec" do 14 | bundle 'gem test' 15 | app = bundled_app("test") 16 | FileUtils.rm(File.join(app.to_s, 'test.gemspec')) 17 | proc { Bundler::GemHelper.new(app.to_s) }.should raise_error(/Unable to determine name/) 18 | end 19 | 20 | it "should fail when there are two gemspecs and the name isn't specified" do 21 | bundle 'gem test' 22 | app = bundled_app("test") 23 | File.open(File.join(app.to_s, 'test2.gemspec'), 'w') {|f| f << ''} 24 | proc { Bundler::GemHelper.new(app.to_s) }.should raise_error(/Unable to determine name/) 25 | end 26 | end 27 | 28 | context "gem management" do 29 | def mock_confirm_message(message) 30 | Bundler.ui.should_receive(:confirm).with(message) 31 | end 32 | 33 | def mock_build_message 34 | mock_confirm_message "test 0.0.1 built to pkg/test-0.0.1.gem" 35 | end 36 | 37 | before(:each) do 38 | bundle 'gem test' 39 | @app = bundled_app("test") 40 | @gemspec = File.read("#{@app.to_s}/test.gemspec") 41 | File.open("#{@app.to_s}/test.gemspec", 'w'){|f| f << @gemspec.gsub('TODO: ', '') } 42 | @helper = Bundler::GemHelper.new(@app.to_s) 43 | end 44 | 45 | it "uses a shell UI for output" do 46 | Bundler.ui.should be_a(Bundler::UI::Shell) 47 | end 48 | 49 | describe 'build' do 50 | it "builds" do 51 | mock_build_message 52 | @helper.build_gem 53 | bundled_app('test/pkg/test-0.0.1.gem').should exist 54 | end 55 | 56 | it "raises an appropriate error when the build fails" do 57 | # break the gemspec by adding back the TODOs... 58 | File.open("#{@app.to_s}/test.gemspec", 'w'){|f| f << @gemspec } 59 | proc { @helper.build_gem }.should raise_error(/TODO/) 60 | end 61 | end 62 | 63 | describe 'install' do 64 | it "installs" do 65 | mock_build_message 66 | mock_confirm_message "test (0.0.1) installed" 67 | @helper.install_gem 68 | bundled_app('test/pkg/test-0.0.1.gem').should exist 69 | %x{gem list}.should include("test (0.0.1)") 70 | end 71 | 72 | it "raises an appropriate error when the install fails" do 73 | @helper.should_receive(:build_gem) do 74 | # write an invalid gem file, so we can simulate install failure... 75 | FileUtils.mkdir_p(File.join(@app.to_s, 'pkg')) 76 | path = "#{@app.to_s}/pkg/test-0.0.1.gem" 77 | File.open(path, 'w'){|f| f << "not actually a gem"} 78 | path 79 | end 80 | proc { @helper.install_gem }.should raise_error 81 | end 82 | end 83 | 84 | describe 'release' do 85 | it "shouldn't push if there are uncommitted files" do 86 | proc { @helper.release_gem }.should raise_error(/files that need to be committed/) 87 | end 88 | 89 | it 'raises an appropriate error if there is no git remote' do 90 | Bundler.ui.stub(:confirm => nil, :error => nil) # silence messages 91 | 92 | Dir.chdir(gem_repo1) { 93 | `git init --bare` 94 | } 95 | Dir.chdir(@app) { 96 | `git init` 97 | `git config user.email "you@example.com"` 98 | `git config user.name "name"` 99 | `git commit -a -m "initial commit"` 100 | } 101 | 102 | proc { @helper.release_gem }.should raise_error 103 | end 104 | 105 | it "releases" do 106 | mock_build_message 107 | mock_confirm_message(/Tagged v0.0.1/) 108 | mock_confirm_message("Pushed git commits and tags") 109 | 110 | @helper.should_receive(:rubygem_push).with(bundled_app('test/pkg/test-0.0.1.gem').to_s) 111 | 112 | Dir.chdir(gem_repo1) { 113 | `git init --bare` 114 | } 115 | Dir.chdir(@app) { 116 | `git init` 117 | `git config user.email "you@example.com"` 118 | `git config user.name "name"` 119 | `git remote add origin file://#{gem_repo1}` 120 | `git commit -a -m "initial commit"` 121 | Open3.popen3("git push origin master") # use popen3 to silence output... 122 | `git commit -a -m "another commit"` 123 | } 124 | @helper.release_gem 125 | end 126 | end 127 | end 128 | end 129 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/actions/empty_directory.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | module Actions 3 | 4 | # Creates an empty directory. 5 | # 6 | # ==== Parameters 7 | # destination:: the relative path to the destination root. 8 | # config:: give :verbose => false to not log the status. 9 | # 10 | # ==== Examples 11 | # 12 | # empty_directory "doc" 13 | # 14 | def empty_directory(destination, config={}) 15 | action EmptyDirectory.new(self, destination, config) 16 | end 17 | 18 | # Class which holds create directory logic. This is the base class for 19 | # other actions like create_file and directory. 20 | # 21 | # This implementation is based in Templater actions, created by Jonas Nicklas 22 | # and Michael S. Klishin under MIT LICENSE. 23 | # 24 | class EmptyDirectory #:nodoc: 25 | attr_reader :base, :destination, :given_destination, :relative_destination, :config 26 | 27 | # Initializes given the source and destination. 28 | # 29 | # ==== Parameters 30 | # base:: A Thor::Base instance 31 | # source:: Relative path to the source of this file 32 | # destination:: Relative path to the destination of this file 33 | # config:: give :verbose => false to not log the status. 34 | # 35 | def initialize(base, destination, config={}) 36 | @base, @config = base, { :verbose => true }.merge(config) 37 | self.destination = destination 38 | end 39 | 40 | # Checks if the destination file already exists. 41 | # 42 | # ==== Returns 43 | # Boolean:: true if the file exists, false otherwise. 44 | # 45 | def exists? 46 | ::File.exists?(destination) 47 | end 48 | 49 | def invoke! 50 | invoke_with_conflict_check do 51 | ::FileUtils.mkdir_p(destination) 52 | end 53 | end 54 | 55 | def revoke! 56 | say_status :remove, :red 57 | ::FileUtils.rm_rf(destination) if !pretend? && exists? 58 | given_destination 59 | end 60 | 61 | protected 62 | 63 | # Shortcut for pretend. 64 | # 65 | def pretend? 66 | base.options[:pretend] 67 | end 68 | 69 | # Sets the absolute destination value from a relative destination value. 70 | # It also stores the given and relative destination. Let's suppose our 71 | # script is being executed on "dest", it sets the destination root to 72 | # "dest". The destination, given_destination and relative_destination 73 | # are related in the following way: 74 | # 75 | # inside "bar" do 76 | # empty_directory "baz" 77 | # end 78 | # 79 | # destination #=> dest/bar/baz 80 | # relative_destination #=> bar/baz 81 | # given_destination #=> baz 82 | # 83 | def destination=(destination) 84 | if destination 85 | @given_destination = convert_encoded_instructions(destination.to_s) 86 | @destination = ::File.expand_path(@given_destination, base.destination_root) 87 | @relative_destination = base.relative_to_original_destination_root(@destination) 88 | end 89 | end 90 | 91 | # Filenames in the encoded form are converted. If you have a file: 92 | # 93 | # %class_name%.rb 94 | # 95 | # It gets the class name from the base and replace it: 96 | # 97 | # user.rb 98 | # 99 | def convert_encoded_instructions(filename) 100 | filename.gsub(/%(.*?)%/) do |string| 101 | instruction = $1.strip 102 | base.respond_to?(instruction) ? base.send(instruction) : string 103 | end 104 | end 105 | 106 | # Receives a hash of options and just execute the block if some 107 | # conditions are met. 108 | # 109 | def invoke_with_conflict_check(&block) 110 | if exists? 111 | on_conflict_behavior(&block) 112 | else 113 | say_status :create, :green 114 | block.call unless pretend? 115 | end 116 | 117 | destination 118 | end 119 | 120 | # What to do when the destination file already exists. 121 | # 122 | def on_conflict_behavior(&block) 123 | say_status :exist, :blue 124 | end 125 | 126 | # Shortcut to say_status shell method. 127 | # 128 | def say_status(status, color) 129 | base.shell.say_status status, relative_destination, color if config[:verbose] 130 | end 131 | 132 | end 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /lib/bundler/gem_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path('../vendor', __FILE__) 2 | require 'thor' 3 | require 'bundler' 4 | 5 | module Bundler 6 | class GemHelper 7 | def self.install_tasks(opts = nil) 8 | dir = File.dirname(Rake.application.rakefile_location) 9 | self.new(dir, opts && opts[:name]).install 10 | end 11 | 12 | attr_reader :spec_path, :base, :gemspec 13 | 14 | def initialize(base, name = nil) 15 | Bundler.ui = UI::Shell.new(Thor::Base.shell.new) 16 | @base = base 17 | gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "*.gemspec")] 18 | raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 19 | @spec_path = gemspecs.first 20 | @gemspec = Bundler.load_gemspec(@spec_path) 21 | end 22 | 23 | def install 24 | desc "Build #{name}-#{version}.gem into the pkg directory" 25 | task 'build' do 26 | build_gem 27 | end 28 | 29 | desc "Build and install #{name}-#{version}.gem into system gems" 30 | task 'install' do 31 | install_gem 32 | end 33 | 34 | desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to Rubygems" 35 | task 'release' do 36 | release_gem 37 | end 38 | end 39 | 40 | def build_gem 41 | file_name = nil 42 | sh("gem build #{spec_path}") { |out, code| 43 | raise out unless out[/Successfully/] 44 | file_name = File.basename(built_gem_path) 45 | FileUtils.mkdir_p(File.join(base, 'pkg')) 46 | FileUtils.mv(built_gem_path, 'pkg') 47 | Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}" 48 | } 49 | File.join(base, 'pkg', file_name) 50 | end 51 | 52 | def install_gem 53 | built_gem_path = build_gem 54 | out, code = sh_with_code("gem install #{built_gem_path}") 55 | raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/] 56 | Bundler.ui.confirm "#{name} (#{version}) installed" 57 | end 58 | 59 | def release_gem 60 | guard_clean 61 | guard_already_tagged 62 | built_gem_path = build_gem 63 | tag_version { 64 | git_push 65 | rubygem_push(built_gem_path) 66 | } 67 | end 68 | 69 | protected 70 | def rubygem_push(path) 71 | out, status = sh("gem push #{path}") 72 | raise "Gem push failed due to lack of RubyGems.org credentials." if out[/Enter your RubyGems.org credentials/] 73 | Bundler.ui.confirm "Pushed #{name} #{version} to rubygems.org" 74 | end 75 | 76 | def built_gem_path 77 | Dir[File.join(base, "#{name}-*.gem")].sort_by{|f| File.mtime(f)}.last 78 | end 79 | 80 | def git_push 81 | perform_git_push 82 | perform_git_push ' --tags' 83 | Bundler.ui.confirm "Pushed git commits and tags" 84 | end 85 | 86 | def perform_git_push(options = '') 87 | cmd = "git push #{options}" 88 | out, code = sh_with_code(cmd) 89 | raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0 90 | end 91 | 92 | def guard_already_tagged 93 | if sh('git tag').split(/\n/).include?(version_tag) 94 | raise("This tag has already been committed to the repo.") 95 | end 96 | end 97 | 98 | def guard_clean 99 | clean? or raise("There are files that need to be committed first.") 100 | end 101 | 102 | def clean? 103 | out, code = sh_with_code("git diff --exit-code") 104 | code == 0 105 | end 106 | 107 | def tag_version 108 | sh "git tag -a -m \"Version #{version}\" #{version_tag}" 109 | Bundler.ui.confirm "Tagged #{version_tag}" 110 | yield if block_given? 111 | rescue 112 | Bundler.ui.error "Untagged #{version_tag} due to error" 113 | sh_with_code "git tag -d #{version_tag}" 114 | raise 115 | end 116 | 117 | def version 118 | gemspec.version 119 | end 120 | 121 | def version_tag 122 | "v#{version}" 123 | end 124 | 125 | def name 126 | gemspec.name 127 | end 128 | 129 | def sh(cmd, &block) 130 | out, code = sh_with_code(cmd, &block) 131 | code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out) 132 | end 133 | 134 | def sh_with_code(cmd, &block) 135 | cmd << " 2>&1" 136 | outbuf = '' 137 | Bundler.ui.debug(cmd) 138 | Dir.chdir(base) { 139 | outbuf = `#{cmd}` 140 | if $? == 0 141 | block.call(outbuf) if block 142 | end 143 | } 144 | [outbuf, $?] 145 | end 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /lib/bundler/runtime.rb: -------------------------------------------------------------------------------- 1 | require "digest/sha1" 2 | 3 | module Bundler 4 | class Runtime < Environment 5 | include SharedHelpers 6 | 7 | def setup(*groups) 8 | # Has to happen first 9 | clean_load_path 10 | 11 | specs = groups.any? ? @definition.specs_for(groups) : requested_specs 12 | 13 | setup_environment 14 | cripple_rubygems(specs) 15 | 16 | # Activate the specs 17 | specs.each do |spec| 18 | unless spec.loaded_from 19 | raise GemNotFound, "#{spec.full_name} is missing. Run `bundle` to get it." 20 | end 21 | 22 | if activated_spec = Gem.loaded_specs[spec.name] and activated_spec.version != spec.version 23 | e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ 24 | "but your Gemfile requires #{spec.name} #{spec.version}. Consider using bundle exec." 25 | e.name = spec.name 26 | e.version_requirement = Gem::Requirement.new(spec.version.to_s) 27 | raise e 28 | end 29 | 30 | Gem.loaded_specs[spec.name] = spec 31 | load_paths = spec.load_paths.reject {|path| $LOAD_PATH.include?(path)} 32 | $LOAD_PATH.unshift(*load_paths) 33 | end 34 | 35 | lock 36 | 37 | self 38 | end 39 | 40 | REGEXPS = [ 41 | /^no such file to load -- (.+)$/i, 42 | /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i, 43 | /^Missing API definition file in (.+)$/i, 44 | /^cannot load such file -- (.+)$/i, 45 | ] 46 | 47 | def require(*groups) 48 | groups.map! { |g| g.to_sym } 49 | groups = [:default] if groups.empty? 50 | 51 | @definition.dependencies.each do |dep| 52 | # Skip the dependency if it is not in any of the requested 53 | # groups 54 | next unless ((dep.groups & groups).any? && dep.current_platform?) 55 | 56 | required_file = nil 57 | 58 | begin 59 | # Loop through all the specified autorequires for the 60 | # dependency. If there are none, use the dependency's name 61 | # as the autorequire. 62 | Array(dep.autorequire || dep.name).each do |file| 63 | required_file = file 64 | Kernel.require file 65 | end 66 | rescue LoadError => e 67 | REGEXPS.find { |r| r =~ e.message } 68 | raise if dep.autorequire || $1 != required_file 69 | end 70 | end 71 | end 72 | 73 | def dependencies_for(*groups) 74 | if groups.empty? 75 | dependencies 76 | else 77 | dependencies.select { |d| (groups & d.groups).any? } 78 | end 79 | end 80 | 81 | alias gems specs 82 | 83 | def cache 84 | FileUtils.mkdir_p(cache_path) 85 | 86 | Bundler.ui.info "Updating .gem files in vendor/cache" 87 | specs.each do |spec| 88 | next if spec.name == 'bundler' 89 | spec.source.cache(spec) if spec.source.respond_to?(:cache) 90 | end 91 | prune_cache unless Bundler.settings[:no_prune] 92 | end 93 | 94 | def prune_cache 95 | FileUtils.mkdir_p(cache_path) 96 | 97 | resolve = @definition.resolve 98 | cached = Dir["#{cache_path}/*.gem"] 99 | 100 | cached = cached.delete_if do |path| 101 | spec = Gem::Format.from_file_by_path(path).spec 102 | 103 | resolve.any? do |s| 104 | s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) 105 | end 106 | end 107 | 108 | if cached.any? 109 | Bundler.ui.info "Removing outdated .gem files from vendor/cache" 110 | 111 | cached.each do |path| 112 | Bundler.ui.info " * #{File.basename(path)}" 113 | File.delete(path) 114 | end 115 | end 116 | end 117 | 118 | private 119 | 120 | def cache_path 121 | root.join("vendor/cache") 122 | end 123 | 124 | def setup_environment 125 | begin 126 | ENV["BUNDLE_BIN_PATH"] = Gem.bin_path("bundler", "bundle", VERSION) 127 | rescue Gem::GemNotFoundException 128 | ENV["BUNDLE_BIN_PATH"] = File.expand_path("../../../bin/bundle", __FILE__) 129 | end 130 | 131 | # Set PATH 132 | paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) 133 | paths.unshift "#{Bundler.bundle_path}/bin" 134 | ENV["PATH"] = paths.uniq.join(File::PATH_SEPARATOR) 135 | 136 | # Set BUNDLE_GEMFILE 137 | ENV["BUNDLE_GEMFILE"] = default_gemfile.to_s 138 | 139 | # Set RUBYOPT 140 | rubyopt = [ENV["RUBYOPT"]].compact 141 | if rubyopt.empty? || rubyopt.first !~ /-rbundler\/setup/ 142 | rubyopt.unshift "-rbundler/setup" 143 | rubyopt.unshift "-I#{File.expand_path('../..', __FILE__)}" 144 | ENV["RUBYOPT"] = rubyopt.join(' ') 145 | end 146 | end 147 | end 148 | end 149 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.unshift File.expand_path("../lib", __FILE__) 3 | require 'bundler/gem_helper' 4 | Bundler::GemHelper.install_tasks 5 | 6 | def sudo? 7 | ENV['BUNDLER_SUDO_TESTS'] 8 | end 9 | 10 | begin 11 | require 'rspec/core/rake_task' 12 | require 'ronn' 13 | 14 | desc "Run specs" 15 | RSpec::Core::RakeTask.new do |t| 16 | t.rspec_opts = %w(-fs --color) 17 | t.ruby_opts = %w(-w) 18 | end 19 | task :spec => "man:build" 20 | 21 | begin 22 | require 'ci/reporter/rake/rspec' 23 | 24 | namespace :ci do 25 | desc "Run specs with Hudson output" 26 | RSpec::Core::RakeTask.new(:spec) 27 | task :spec => ["ci:setup:rspec", "man:build"] 28 | end 29 | 30 | rescue LoadError 31 | namespace :ci do 32 | task :spec do 33 | abort "Run `rake ci:deps` to be able to run the CI specs" 34 | end 35 | 36 | desc "Install CI dependencies" 37 | task :deps do 38 | sh "gem list ci_reporter | (grep 'ci_reporter' 1> /dev/null) || gem install ci_reporter --no-ri --no-rdoc" 39 | end 40 | task :deps => "spec:deps" 41 | end 42 | end 43 | 44 | namespace :spec do 45 | desc "Run the spec suite with the sudo tests" 46 | task :sudo => ["set_sudo", "clean", "spec"] 47 | 48 | task :set_sudo do 49 | ENV['BUNDLER_SUDO_TESTS'] = '1' 50 | end 51 | 52 | task :clean do 53 | if sudo? 54 | system "sudo rm -rf #{File.expand_path('../tmp', __FILE__)}" 55 | else 56 | rm_rf 'tmp' 57 | end 58 | end 59 | 60 | namespace :rubygems do 61 | # Rubygems 1.3.5, 1.3.6, and HEAD specs 62 | rubyopt = ENV["RUBYOPT"] 63 | %w(master REL_1_3_5 REL_1_3_6).each do |rg| 64 | desc "Run specs with Rubygems #{rg}" 65 | RSpec::Core::RakeTask.new(rg) do |t| 66 | t.rspec_opts = %w(-fs --color) 67 | t.ruby_opts = %w(-w) 68 | end 69 | 70 | task "clone_rubygems_#{rg}" do 71 | unless File.directory?("tmp/rubygems_#{rg}") 72 | system("git clone git://github.com/jbarnette/rubygems.git tmp/rubygems_#{rg} && cd tmp/rubygems_#{rg} && git reset --hard #{rg}") 73 | end 74 | ENV["RUBYOPT"] = "-I#{File.expand_path("tmp/rubygems_#{rg}/lib")} #{rubyopt}" 75 | end 76 | 77 | task rg => "clone_rubygems_#{rg}" 78 | task "rubygems:all" => rg 79 | end 80 | end 81 | 82 | namespace :ruby do 83 | # Ruby 1.8.6, 1.8.7, and 1.9.2 specs 84 | task "ensure_rvm" do 85 | raise "RVM is not available" unless File.exist?(File.expand_path("~/.rvm/scripts/rvm")) 86 | end 87 | 88 | %w(1.8.6-p399 1.8.7-p302 1.9.2-p0).each do |ruby| 89 | ruby_cmd = File.expand_path("~/.rvm/bin/ruby-#{ruby}") 90 | 91 | desc "Run specs on Ruby #{ruby}" 92 | RSpec::Core::RakeTask.new(ruby) do |t| 93 | t.rspec_opts = %w(-fs --color) 94 | t.ruby_opts = %w(-w) 95 | end 96 | 97 | task "ensure_ruby_#{ruby}" do 98 | raise "Could not find Ruby #{ruby} at #{ruby_cmd}" unless File.exist?(ruby_cmd) 99 | end 100 | 101 | task "ensure_ruby_#{ruby}" => "ensure_rvm" 102 | task ruby => "ensure_ruby_#{ruby}" 103 | task "ruby:all" => ruby 104 | end 105 | end 106 | 107 | end 108 | 109 | rescue LoadError 110 | task :spec do 111 | abort "Run `rake spec:deps` to be able to run the specs" 112 | end 113 | 114 | namespace :spec do 115 | desc "Ensure spec dependencies are installed" 116 | task :deps do 117 | sh "gem list ronn | (grep 'ronn' 1> /dev/null) || gem install ronn --no-ri --no-rdoc" 118 | sh "gem list rspec | (grep 'rspec (2.0' 1> /dev/null) || gem install rspec --no-ri --no-rdoc" 119 | end 120 | end 121 | 122 | end 123 | 124 | namespace :man do 125 | directory "lib/bundler/man" 126 | 127 | Dir["man/*.ronn"].each do |ronn| 128 | basename = File.basename(ronn, ".ronn") 129 | roff = "lib/bundler/man/#{basename}" 130 | 131 | file roff => ["lib/bundler/man", ronn] do 132 | sh "ronn --roff --pipe #{ronn} > #{roff}" 133 | end 134 | 135 | file "#{roff}.txt" => roff do 136 | sh "groff -Wall -mtty-char -mandoc -Tascii #{roff} | col -b > #{roff}.txt" 137 | end 138 | 139 | task :build_all_pages => "#{roff}.txt" 140 | end 141 | 142 | desc "Build the man pages" 143 | task :build => "man:build_all_pages" 144 | 145 | desc "Clean up from the built man pages" 146 | task :clean do 147 | rm_rf "lib/bundler/man" 148 | end 149 | end 150 | 151 | namespace :vendor do 152 | desc "Build the vendor dir" 153 | task :build => :clean do 154 | sh "git clone git://github.com/wycats/thor.git lib/bundler/vendor/tmp" 155 | sh "mv lib/bundler/vendor/tmp/lib/* lib/bundler/vendor/" 156 | rm_rf "lib/bundler/vendor/tmp" 157 | end 158 | 159 | desc "Clean the vendor dir" 160 | task :clean do 161 | rm_rf "lib/bundler/vendor" 162 | end 163 | end 164 | 165 | task :default => :spec 166 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/shell/html.rb: -------------------------------------------------------------------------------- 1 | require 'thor/shell/basic' 2 | 3 | class Thor 4 | module Shell 5 | # Inherit from Thor::Shell::Basic and add set_color behavior. Check 6 | # Thor::Shell::Basic to see all available methods. 7 | # 8 | class HTML < Basic 9 | # The start of an HTML bold sequence. 10 | BOLD = "" 11 | # The end of an HTML bold sequence. 12 | END_BOLD = "" 13 | 14 | # Embed in a String to clear previous color selection. 15 | CLEAR = "" 16 | 17 | # Set the terminal's foreground HTML color to black. 18 | BLACK = '' 19 | # Set the terminal's foreground HTML color to red. 20 | RED = '' 21 | # Set the terminal's foreground HTML color to green. 22 | GREEN = '' 23 | # Set the terminal's foreground HTML color to yellow. 24 | YELLOW = '' 25 | # Set the terminal's foreground HTML color to blue. 26 | BLUE = '' 27 | # Set the terminal's foreground HTML color to magenta. 28 | MAGENTA = '' 29 | # Set the terminal's foreground HTML color to cyan. 30 | CYAN = '' 31 | # Set the terminal's foreground HTML color to white. 32 | WHITE = '' 33 | 34 | # Set the terminal's background HTML color to black. 35 | ON_BLACK = '' 36 | # Set the terminal's background HTML color to red. 37 | ON_RED = '' 38 | # Set the terminal's background HTML color to green. 39 | ON_GREEN = '' 40 | # Set the terminal's background HTML color to yellow. 41 | ON_YELLOW = '' 42 | # Set the terminal's background HTML color to blue. 43 | ON_BLUE = '' 44 | # Set the terminal's background HTML color to magenta. 45 | ON_MAGENTA = '' 46 | # Set the terminal's background HTML color to cyan. 47 | ON_CYAN = '' 48 | # Set the terminal's background HTML color to white. 49 | ON_WHITE = '' 50 | 51 | # Set color by using a string or one of the defined constants. If a third 52 | # option is set to true, it also adds bold to the string. This is based 53 | # on Highline implementation and it automatically appends CLEAR to the end 54 | # of the returned String. 55 | # 56 | def set_color(string, color, bold=false) 57 | color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) 58 | bold, end_bold = bold ? [BOLD, END_BOLD] : ['', ''] 59 | "#{bold}#{color}#{string}#{CLEAR}#{end_bold}" 60 | end 61 | 62 | # Ask something to the user and receives a response. 63 | # 64 | # ==== Example 65 | # ask("What is your name?") 66 | # 67 | # TODO: Implement #ask for Thor::Shell::HTML 68 | def ask(statement, color=nil) 69 | raise NotImplementedError, "Implement #ask for Thor::Shell::HTML" 70 | end 71 | 72 | protected 73 | 74 | # Overwrite show_diff to show diff with colors if Diff::LCS is 75 | # available. 76 | # 77 | def show_diff(destination, content) #:nodoc: 78 | if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil? 79 | actual = File.binread(destination).to_s.split("\n") 80 | content = content.to_s.split("\n") 81 | 82 | Diff::LCS.sdiff(actual, content).each do |diff| 83 | output_diff_line(diff) 84 | end 85 | else 86 | super 87 | end 88 | end 89 | 90 | def output_diff_line(diff) #:nodoc: 91 | case diff.action 92 | when '-' 93 | say "- #{diff.old_element.chomp}", :red, true 94 | when '+' 95 | say "+ #{diff.new_element.chomp}", :green, true 96 | when '!' 97 | say "- #{diff.old_element.chomp}", :red, true 98 | say "+ #{diff.new_element.chomp}", :green, true 99 | else 100 | say " #{diff.old_element.chomp}", nil, true 101 | end 102 | end 103 | 104 | # Check if Diff::LCS is loaded. If it is, use it to create pretty output 105 | # for diff. 106 | # 107 | def diff_lcs_loaded? #:nodoc: 108 | return true if defined?(Diff::LCS) 109 | return @diff_lcs_loaded unless @diff_lcs_loaded.nil? 110 | 111 | @diff_lcs_loaded = begin 112 | require 'diff/lcs' 113 | true 114 | rescue LoadError 115 | false 116 | end 117 | end 118 | 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /spec/install/gems/platform_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe "bundle install across platforms" do 4 | it "maintains the same lockfile if all gems are compatible across platforms" do 5 | lockfile <<-G 6 | GEM 7 | remote: file:#{gem_repo1}/ 8 | specs: 9 | rack (0.9.1) 10 | 11 | PLATFORMS 12 | #{not_local} 13 | 14 | DEPENDENCIES 15 | rack 16 | G 17 | 18 | install_gemfile <<-G 19 | source "file://#{gem_repo1}" 20 | 21 | gem "rack" 22 | G 23 | 24 | should_be_installed "rack 0.9.1" 25 | end 26 | 27 | it "pulls in the correct platform specific gem" do 28 | lockfile <<-G 29 | GEM 30 | remote: file:#{gem_repo1} 31 | specs: 32 | platform_specific (1.0) 33 | platform_specific (1.0-java) 34 | platform_specific (1.0-x86-mswin32) 35 | 36 | PLATFORMS 37 | ruby 38 | 39 | DEPENDENCIES 40 | platform_specific 41 | G 42 | 43 | simulate_platform "java" 44 | install_gemfile <<-G 45 | source "file://#{gem_repo1}" 46 | 47 | gem "platform_specific" 48 | G 49 | 50 | should_be_installed "platform_specific 1.0 JAVA" 51 | end 52 | 53 | it "works with gems that have different dependencies" do 54 | simulate_platform "java" 55 | install_gemfile <<-G 56 | source "file://#{gem_repo1}" 57 | 58 | gem "nokogiri" 59 | G 60 | 61 | should_be_installed "nokogiri 1.4.2 JAVA", "weakling 0.0.3" 62 | 63 | simulate_new_machine 64 | 65 | simulate_platform "ruby" 66 | install_gemfile <<-G 67 | source "file://#{gem_repo1}" 68 | 69 | gem "nokogiri" 70 | G 71 | 72 | should_be_installed "nokogiri 1.4.2" 73 | should_not_be_installed "weakling" 74 | end 75 | 76 | it "works the other way with gems that have different dependencies" do 77 | simulate_platform "ruby" 78 | install_gemfile <<-G 79 | source "file://#{gem_repo1}" 80 | 81 | gem "nokogiri" 82 | G 83 | 84 | simulate_platform "java" 85 | bundle "install" 86 | 87 | should_be_installed "nokogiri 1.4.2 JAVA", "weakling 0.0.3" 88 | end 89 | 90 | it "fetches gems again after changing the version of Ruby" do 91 | gemfile <<-G 92 | source "file://#{gem_repo1}" 93 | 94 | gem "rack", "1.0.0" 95 | G 96 | 97 | bundle "install --path vendor/bundle" 98 | 99 | vendored_gems("gems/rack-1.0.0").should exist 100 | end 101 | 102 | it "works after switching Rubies" do 103 | gemfile <<-G 104 | source "file://#{gem_repo1}" 105 | 106 | gem "rack", "1.0.0" 107 | G 108 | 109 | bundle "install --path vendor/bundle" 110 | 111 | new_version = Gem::ConfigMap[:ruby_version] == "1.8" ? "1.9.1" : "1.8" 112 | FileUtils.mv(vendored_gems, bundled_app("vendor/bundle/#{Gem.ruby_engine}/#{new_version}")) 113 | 114 | bundle "install --path ./vendor/bundle" 115 | vendored_gems("gems/rack-1.0.0").should exist 116 | end 117 | end 118 | 119 | describe "bundle install with platform conditionals" do 120 | it "installs gems tagged w/ the current platforms" do 121 | install_gemfile <<-G 122 | source "file://#{gem_repo1}" 123 | 124 | platforms :#{local_tag} do 125 | gem "nokogiri" 126 | end 127 | G 128 | 129 | should_be_installed "nokogiri 1.4.2" 130 | end 131 | 132 | it "does not install gems tagged w/ another platforms" do 133 | install_gemfile <<-G 134 | source "file://#{gem_repo1}" 135 | gem "rack" 136 | platforms :#{not_local_tag} do 137 | gem "nokogiri" 138 | end 139 | G 140 | 141 | should_be_installed "rack 1.0" 142 | should_not_be_installed "nokogiri 1.4.2" 143 | end 144 | 145 | it "installs gems tagged w/ the current platforms inline" do 146 | install_gemfile <<-G 147 | source "file://#{gem_repo1}" 148 | gem "nokogiri", :platforms => :#{local_tag} 149 | G 150 | should_be_installed "nokogiri 1.4.2" 151 | end 152 | 153 | it "does not install gems tagged w/ another platforms inline" do 154 | install_gemfile <<-G 155 | source "file://#{gem_repo1}" 156 | gem "rack" 157 | gem "nokogiri", :platforms => :#{not_local_tag} 158 | G 159 | should_be_installed "rack 1.0" 160 | should_not_be_installed "nokogiri 1.4.2" 161 | end 162 | 163 | it "installs gems tagged w/ the current platform inline" do 164 | install_gemfile <<-G 165 | source "file://#{gem_repo1}" 166 | gem "nokogiri", :platform => :#{local_tag} 167 | G 168 | should_be_installed "nokogiri 1.4.2" 169 | end 170 | 171 | it "doesn't install gems tagged w/ another platform inline" do 172 | install_gemfile <<-G 173 | source "file://#{gem_repo1}" 174 | gem "nokogiri", :platform => :#{not_local_tag} 175 | G 176 | should_not_be_installed "nokogiri 1.4.2" 177 | end 178 | 179 | it "does not blow up on sources with all platform-excluded specs" do 180 | git = build_git "foo" 181 | 182 | install_gemfile <<-G 183 | platform :#{not_local_tag} do 184 | gem "foo", :git => "#{lib_path('foo-1.0')}" 185 | end 186 | G 187 | 188 | bundle :show, :exitstatus => true 189 | exitstatus.should == 0 190 | end 191 | 192 | end 193 | -------------------------------------------------------------------------------- /lib/bundler/shared_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | require 'rubygems' 3 | Gem.source_index # ensure Rubygems is fully loaded in Ruby 1.9 4 | 5 | module Gem 6 | class Dependency 7 | if !instance_methods.map { |m| m.to_s }.include?("requirement") 8 | def requirement 9 | version_requirements 10 | end 11 | end 12 | end 13 | end 14 | 15 | module Bundler 16 | module SharedHelpers 17 | attr_accessor :gem_loaded 18 | 19 | def default_gemfile 20 | gemfile = find_gemfile 21 | raise GemfileNotFound, "Could not locate Gemfile" unless gemfile 22 | Pathname.new(gemfile) 23 | end 24 | 25 | def default_lockfile 26 | Pathname.new("#{default_gemfile}.lock") 27 | end 28 | 29 | def in_bundle? 30 | find_gemfile 31 | end 32 | 33 | private 34 | 35 | def find_gemfile 36 | given = ENV['BUNDLE_GEMFILE'] 37 | return given if given && !given.empty? 38 | 39 | previous = nil 40 | current = File.expand_path(Dir.pwd) 41 | 42 | until !File.directory?(current) || current == previous 43 | if ENV['BUNDLE_SPEC_RUN'] 44 | # avoid stepping above the tmp directory when testing 45 | return nil if File.file?(File.join(current, 'bundler.gemspec')) 46 | end 47 | 48 | # otherwise return the Gemfile if it's there 49 | filename = File.join(current, 'Gemfile') 50 | return filename if File.file?(filename) 51 | current, previous = File.expand_path("..", current), current 52 | end 53 | end 54 | 55 | def clean_load_path 56 | # handle 1.9 where system gems are always on the load path 57 | if defined?(::Gem) 58 | me = File.expand_path("../../", __FILE__) 59 | $LOAD_PATH.reject! do |p| 60 | next if File.expand_path(p) =~ /^#{me}/ 61 | p != File.dirname(__FILE__) && 62 | Gem.path.any?{|gp| p =~ /^#{gp}/ } 63 | end 64 | $LOAD_PATH.uniq! 65 | end 66 | end 67 | 68 | def reverse_rubygems_kernel_mixin 69 | # Disable rubygems' gem activation system 70 | ::Kernel.class_eval do 71 | if private_method_defined?(:gem_original_require) 72 | alias rubygems_require require 73 | alias require gem_original_require 74 | end 75 | 76 | undef gem 77 | end 78 | end 79 | 80 | def cripple_rubygems(specs) 81 | reverse_rubygems_kernel_mixin 82 | 83 | executables = specs.map { |s| s.executables }.flatten 84 | Gem.source_index # ensure RubyGems is fully loaded 85 | 86 | ::Kernel.send(:define_method, :gem) do |dep, *reqs| 87 | if executables.include? File.basename(caller.first.split(':').first) 88 | return 89 | end 90 | opts = reqs.last.is_a?(Hash) ? reqs.pop : {} 91 | 92 | unless dep.respond_to?(:name) && dep.respond_to?(:requirement) 93 | dep = Gem::Dependency.new(dep, reqs) 94 | end 95 | 96 | spec = specs.find { |s| s.name == dep.name } 97 | 98 | if spec.nil? 99 | e = Gem::LoadError.new "#{dep.name} is not part of the bundle. Add it to Gemfile." 100 | e.name = dep.name 101 | e.version_requirement = dep.requirement 102 | raise e 103 | elsif dep !~ spec 104 | e = Gem::LoadError.new "can't activate #{dep}, already activated #{spec.full_name}. " \ 105 | "Make sure all dependencies are added to Gemfile." 106 | e.name = dep.name 107 | e.version_requirement = dep.requirement 108 | raise e 109 | end 110 | 111 | true 112 | end 113 | 114 | # === Following hacks are to improve on the generated bin wrappers === 115 | 116 | # Yeah, talk about a hack 117 | source_index_class = (class << Gem::SourceIndex ; self ; end) 118 | source_index_class.send(:remove_method, :from_gems_in) 119 | source_index_class.send(:define_method, :from_gems_in) do |*args| 120 | source_index = Gem::SourceIndex.new 121 | source_index.spec_dirs = *args 122 | source_index.add_specs(*specs) 123 | source_index 124 | end 125 | 126 | # OMG more hacks 127 | gem_class = (class << Gem ; self ; end) 128 | gem_class.send(:remove_method, :refresh) 129 | gem_class.send(:define_method, :refresh) { } 130 | gem_class.send(:remove_method, :bin_path) 131 | gem_class.send(:define_method, :bin_path) do |name, *args| 132 | exec_name, *reqs = args 133 | 134 | if exec_name == 'bundle' 135 | return ENV['BUNDLE_BIN_PATH'] 136 | end 137 | 138 | spec = nil 139 | 140 | if exec_name 141 | spec = specs.find { |s| s.executables.include?(exec_name) } 142 | spec or raise Gem::Exception, "can't find executable #{exec_name}" 143 | else 144 | spec = specs.find { |s| s.name == name } 145 | exec_name = spec.default_executable or raise Gem::Exception, "no default executable for #{spec.full_name}" 146 | end 147 | 148 | gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) 149 | gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) 150 | File.exist?(gem_bin) ? gem_bin : gem_from_path_bin 151 | end 152 | 153 | Gem.clear_paths 154 | end 155 | 156 | extend self 157 | end 158 | end 159 | -------------------------------------------------------------------------------- /lib/bundler/vendor/thor/parser/options.rb: -------------------------------------------------------------------------------- 1 | class Thor 2 | # This is a modified version of Daniel Berger's Getopt::Long class, licensed 3 | # under Ruby's license. 4 | # 5 | class Options < Arguments #:nodoc: 6 | LONG_RE = /^(--\w+(?:-\w+)*)$/ 7 | SHORT_RE = /^(-[a-z])$/i 8 | EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i 9 | SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args 10 | SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i 11 | 12 | # Receives a hash and makes it switches. 13 | def self.to_switches(options) 14 | options.map do |key, value| 15 | case value 16 | when true 17 | "--#{key}" 18 | when Array 19 | "--#{key} #{value.map{ |v| v.inspect }.join(' ')}" 20 | when Hash 21 | "--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}" 22 | when nil, false 23 | "" 24 | else 25 | "--#{key} #{value.inspect}" 26 | end 27 | end.join(" ") 28 | end 29 | 30 | # Takes a hash of Thor::Option and a hash with defaults. 31 | def initialize(hash_options={}, defaults={}) 32 | options = hash_options.values 33 | super(options) 34 | 35 | # Add defaults 36 | defaults.each do |key, value| 37 | @assigns[key.to_s] = value 38 | @non_assigned_required.delete(hash_options[key]) 39 | end 40 | 41 | @shorts, @switches, @unknown = {}, {}, [] 42 | 43 | options.each do |option| 44 | @switches[option.switch_name] = option 45 | 46 | option.aliases.each do |short| 47 | @shorts[short.to_s] ||= option.switch_name 48 | end 49 | end 50 | end 51 | 52 | def parse(args) 53 | @pile = args.dup 54 | 55 | while peek 56 | if current_is_switch? 57 | case shift 58 | when SHORT_SQ_RE 59 | unshift($1.split('').map { |f| "-#{f}" }) 60 | next 61 | when EQ_RE, SHORT_NUM 62 | unshift($2) 63 | switch = $1 64 | when LONG_RE, SHORT_RE 65 | switch = $1 66 | end 67 | 68 | switch = normalize_switch(switch) 69 | option = switch_option(switch) 70 | @assigns[option.human_name] = parse_peek(switch, option) 71 | elsif current_is_switch_formatted? 72 | @unknown << shift 73 | else 74 | shift 75 | end 76 | end 77 | 78 | check_requirement! 79 | 80 | assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) 81 | assigns.freeze 82 | assigns 83 | end 84 | 85 | def check_unknown! 86 | raise UnknownArgumentError, "Unknown switches '#{@unknown.join(', ')}'" unless @unknown.empty? 87 | end 88 | 89 | protected 90 | 91 | # Returns true if the current value in peek is a registered switch. 92 | # 93 | def current_is_switch? 94 | case peek 95 | when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM 96 | switch?($1) 97 | when SHORT_SQ_RE 98 | $1.split('').any? { |f| switch?("-#{f}") } 99 | end 100 | end 101 | 102 | def switch_formatted?(arg) 103 | case arg 104 | when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE 105 | true 106 | else 107 | false 108 | end 109 | end 110 | 111 | def current_is_switch_formatted? 112 | switch_formatted? peek 113 | end 114 | 115 | def switch?(arg) 116 | switch_option(arg) || @shorts.key?(arg) 117 | end 118 | 119 | def switch_option(arg) 120 | if match = no_or_skip?(arg) 121 | @switches[arg] || @switches["--#{match}"] 122 | else 123 | @switches[arg] 124 | end 125 | end 126 | 127 | # Check if the given argument is actually a shortcut. 128 | # 129 | def normalize_switch(arg) 130 | @shorts.key?(arg) ? @shorts[arg] : arg 131 | end 132 | 133 | # Parse boolean values which can be given as --foo=true, --foo or --no-foo. 134 | # 135 | def parse_boolean(switch) 136 | if current_is_value? 137 | if ["true", "TRUE", "t", "T", true].include?(peek) 138 | shift 139 | true 140 | elsif ["false", "FALSE", "f", "F", false].include?(peek) 141 | shift 142 | false 143 | else 144 | true 145 | end 146 | else 147 | @switches.key?(switch) || !no_or_skip?(switch) 148 | end 149 | end 150 | 151 | # Parse the value at the peek analyzing if it requires an input or not. 152 | # 153 | def parse_peek(switch, option) 154 | if current_is_switch_formatted? || last? 155 | if option.boolean? 156 | # No problem for boolean types 157 | elsif no_or_skip?(switch) 158 | return nil # User set value to nil 159 | elsif option.string? && !option.required? 160 | # Return the default if there is one, else the human name 161 | return option.lazy_default || option.default || option.human_name 162 | elsif option.lazy_default 163 | return option.lazy_default 164 | else 165 | raise MalformattedArgumentError, "No value provided for option '#{switch}'" 166 | end 167 | end 168 | 169 | @non_assigned_required.delete(option) 170 | send(:"parse_#{option.type}", switch) 171 | end 172 | 173 | end 174 | end 175 | -------------------------------------------------------------------------------- /lib/bundler/rubygems_ext.rb: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | 3 | if defined?(Gem::QuickLoader) 4 | # Gem Prelude makes me a sad panda :'( 5 | Gem::QuickLoader.load_full_rubygems_library 6 | end 7 | 8 | require 'rubygems' 9 | require 'rubygems/specification' 10 | 11 | module Gem 12 | @loaded_stacks = Hash.new { |h,k| h[k] = [] } 13 | 14 | class Specification 15 | attr_accessor :source, :location, :relative_loaded_from 16 | 17 | alias_method :rg_full_gem_path, :full_gem_path 18 | alias_method :rg_loaded_from, :loaded_from 19 | 20 | def full_gem_path 21 | source.respond_to?(:path) ? 22 | Pathname.new(loaded_from).dirname.expand_path.to_s : 23 | rg_full_gem_path 24 | end 25 | 26 | def loaded_from 27 | relative_loaded_from ? 28 | source.path.join(relative_loaded_from).to_s : 29 | rg_loaded_from 30 | end 31 | 32 | def load_paths 33 | require_paths.map do |require_path| 34 | if require_path.include?(full_gem_path) 35 | require_path 36 | else 37 | File.join(full_gem_path, require_path) 38 | end 39 | end 40 | end 41 | 42 | def groups 43 | @groups ||= [] 44 | end 45 | 46 | def git_version 47 | if @loaded_from && File.exist?(File.join(full_gem_path, ".git")) 48 | sha = Dir.chdir(full_gem_path){ `git rev-parse HEAD`.strip } 49 | " #{sha[0..6]}" 50 | end 51 | end 52 | 53 | def to_gemfile(path = nil) 54 | gemfile = "source :gemcutter\n" 55 | gemfile << dependencies_to_gemfile(nondevelopment_dependencies) 56 | unless development_dependencies.empty? 57 | gemfile << "\n" 58 | gemfile << dependencies_to_gemfile(development_dependencies, :development) 59 | end 60 | gemfile 61 | end 62 | 63 | def nondevelopment_dependencies 64 | dependencies - development_dependencies 65 | end 66 | 67 | def add_bundler_dependencies(*groups) 68 | Bundler.ui.warn "#add_bundler_dependencies is deprecated and will " \ 69 | "be removed in Bundler 1.0. Instead, please use the #gemspec method " \ 70 | "in your Gemfile, which will pull in any dependencies specified in " \ 71 | "your gemspec" 72 | 73 | groups = [:default] if groups.empty? 74 | Bundler.definition.dependencies.each do |dep| 75 | if dep.groups.include?(:development) 76 | self.add_development_dependency(dep.name, dep.requirement.to_s) 77 | elsif (dep.groups & groups).any? 78 | self.add_dependency(dep.name, dep.requirement.to_s) 79 | end 80 | end 81 | end 82 | 83 | private 84 | 85 | def dependencies_to_gemfile(dependencies, group = nil) 86 | gemfile = '' 87 | if dependencies.any? 88 | gemfile << "group :#{group} do\n" if group 89 | dependencies.each do |dependency| 90 | gemfile << ' ' if group 91 | gemfile << %|gem "#{dependency.name}"| 92 | req = dependency.requirements_list.first 93 | gemfile << %|, "#{req}"| if req 94 | gemfile << "\n" 95 | end 96 | gemfile << "end\n" if group 97 | end 98 | gemfile 99 | end 100 | 101 | end 102 | 103 | class Dependency 104 | attr_accessor :source, :groups 105 | 106 | alias eql? == 107 | 108 | def to_yaml_properties 109 | instance_variables.reject { |p| ["@source", "@groups"].include?(p.to_s) } 110 | end 111 | 112 | def to_lock 113 | out = " #{name}" 114 | unless requirement == Gem::Requirement.default 115 | out << " (#{requirement.to_s})" 116 | end 117 | out 118 | end 119 | 120 | def matches_spec?(spec) 121 | # name can be a Regexp, so use === 122 | return false unless name === spec.name 123 | return true if requirement.none? 124 | 125 | requirement.satisfied_by?(spec.version) 126 | end unless allocate.respond_to?(:matches_spec?) 127 | end 128 | 129 | class Requirement 130 | def none? 131 | @none ||= (to_s == ">= 0") 132 | end unless allocate.respond_to?(:none?) 133 | end 134 | 135 | class Platform 136 | JAVA = Gem::Platform.new('java') 137 | MSWIN = Gem::Platform.new('mswin32') 138 | MINGW = Gem::Platform.new('x86-mingw32') 139 | 140 | def hash 141 | @cpu.hash ^ @os.hash ^ @version.hash 142 | end 143 | 144 | alias eql? == 145 | end 146 | end 147 | 148 | module Bundler 149 | class DepProxy 150 | 151 | attr_reader :required_by, :__platform, :dep 152 | 153 | def initialize(dep, platform) 154 | @dep, @__platform, @required_by = dep, platform, [] 155 | end 156 | 157 | def hash 158 | @hash ||= dep.hash 159 | end 160 | 161 | def ==(o) 162 | dep == o.dep && __platform == o.__platform 163 | end 164 | 165 | alias eql? == 166 | 167 | def type 168 | @dep.type 169 | end 170 | 171 | def to_s 172 | @dep.to_s 173 | end 174 | 175 | private 176 | 177 | def method_missing(*args) 178 | @dep.send(*args) 179 | end 180 | 181 | end 182 | 183 | module GemHelpers 184 | 185 | GENERIC_CACHE = {} 186 | GENERICS = [ 187 | Gem::Platform::JAVA, 188 | Gem::Platform::MSWIN, 189 | Gem::Platform::MINGW, 190 | Gem::Platform::RUBY 191 | ] 192 | 193 | def generic(p) 194 | return p if p == Gem::Platform::RUBY 195 | 196 | GENERIC_CACHE[p] ||= begin 197 | found = GENERICS.find do |p2| 198 | p2.is_a?(Gem::Platform) && p.os == p2.os 199 | end 200 | found || Gem::Platform::RUBY 201 | end 202 | end 203 | end 204 | 205 | module MatchPlatform 206 | include GemHelpers 207 | 208 | def match_platform(p) 209 | Gem::Platform::RUBY == platform or 210 | platform.nil? or p == platform or 211 | generic(Gem::Platform.new(platform)) == p 212 | end 213 | end 214 | end 215 | 216 | module Gem 217 | class Specification 218 | include Bundler::MatchPlatform 219 | end 220 | end 221 | --------------------------------------------------------------------------------