summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml17
-rw-r--r--CHANGELOG.md34
-rw-r--r--ISSUES.md2
-rw-r--r--README.md2
-rw-r--r--Rakefile11
-rwxr-xr-xbin/bundle35
-rw-r--r--lib/bundler.rb46
-rw-r--r--lib/bundler/cli.rb129
-rw-r--r--lib/bundler/definition.rb96
-rw-r--r--lib/bundler/dsl.rb45
-rw-r--r--lib/bundler/fetcher.rb5
-rw-r--r--lib/bundler/friendly_errors.rb22
-rw-r--r--lib/bundler/gem_helper.rb22
-rw-r--r--lib/bundler/graph.rb20
-rw-r--r--lib/bundler/installer.rb35
-rw-r--r--lib/bundler/ruby_version.rb94
-rw-r--r--lib/bundler/runtime.rb2
-rw-r--r--lib/bundler/settings.rb19
-rw-r--r--lib/bundler/source.rb465
-rw-r--r--lib/bundler/templates/newgem/README.md.tt2
-rw-r--r--lib/bundler/vendor/thor/parser/options.rb3
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--man/bundle-config.ronn40
-rw-r--r--man/bundle-install.ronn6
-rw-r--r--man/bundle-package.ronn6
-rw-r--r--man/gemfile.5.ronn46
-rw-r--r--spec/bundler/dsl_spec.rb28
-rw-r--r--spec/bundler/gem_helper_spec.rb31
-rw-r--r--spec/cache/gems_spec.rb11
-rw-r--r--spec/cache/git_spec.rb116
-rw-r--r--spec/cache/path_spec.rb94
-rw-r--r--spec/install/deprecated_spec.rb36
-rw-r--r--spec/install/gems/dependency_api_spec.rb29
-rw-r--r--spec/install/git_spec.rb150
-rw-r--r--spec/other/check_spec.rb14
-rw-r--r--spec/other/config_spec.rb142
-rw-r--r--spec/other/newgem_spec.rb2
-rw-r--r--spec/other/platform_spec.rb881
-rw-r--r--spec/support/helpers.rb13
-rw-r--r--spec/support/platforms.rb33
-rw-r--r--spec/support/rubygems_hax/platform.rb13
-rw-r--r--spec/update/gems_spec.rb12
42 files changed, 2433 insertions, 378 deletions
diff --git a/.travis.yml b/.travis.yml
index ca0a5c9ef6..9aa1486030 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,13 +2,6 @@ before_script:
- sudo apt-get install groff -y
- rake spec:deps
-script: rake spec:travis
-
-rvm:
- - 1.8.7
- - 1.9.2
- - 1.9.3
-
env:
- RGV=v1.3.6
- RGV=v1.3.7
@@ -18,6 +11,8 @@ env:
- RGV=v1.7.2
- RGV=v1.8.10
+language: ruby
+
matrix:
exclude:
- rvm: 1.9.2
@@ -37,3 +32,11 @@ notifications:
email:
- travis-ci@andrearko.com
- hone02@gmail.com
+ - sferik@gmail.com
+
+rvm:
+ - 1.8.7
+ - 1.9.2
+ - 1.9.3
+
+script: rake spec:travis
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3f0515ec1..f3d254ade6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,37 @@
+## 1.2.0.pre (May 4, 2012)
+
+Features:
+
+ - bundle package now accepts --all to package git and path dependencies
+ - bundle config now accepts --local, --global and --delete options
+ - It is possible to override a git repository via configuration.
+ For instance, if you have a git dependency on rack, you can force
+ it to use a local repo with `bundle config local.rack ~/path/to/rack`
+ - Cache gemspec loads for performance (@dekellum, #1635)
+ - add --full-index flag to `bundle update` (@fluxx, #1829)
+ - add --quiet flag to `bundle update` (@nashby, #1654)
+ - Add Bundler::GemHelper.gemspec (@knu, #1637)
+ - Graceful handling of Gemfile syntax errors (@koraktor, #1661)
+ - `bundle platform` command
+ - add ruby to DSL, to specify version of ruby
+ - error out if the ruby version doesn't match
+
+Performance:
+
+ - bundle exec shouldn't run Bundler.setup just setting the right rubyopts options is enough (@spastorino, #1598)
+
+Bugfixes:
+
+ - Avoid passing RUBYOPT changes in with_clean_env block (@eric1234, #1604)
+ - Use the same ruby to run subprocesses as is running rake (@brixen)
+
+Documentation:
+
+ - Add :github documentation in DSL (@zofrex, #1848, #1851, #1852)
+ - Add docs for the --no-cache option (@fluxx, #1796)
+ - Add basic documentation for bin_path and bundle_path (@radar)
+ - Add documentation for the run method in Bundler::Installer
+
## 1.1.4 (May 27, 2012)
Bugfixes:
diff --git a/ISSUES.md b/ISSUES.md
index ebbc492250..192c720382 100644
--- a/ISSUES.md
+++ b/ISSUES.md
@@ -4,7 +4,7 @@ So! You're having problems with Bundler. This file is here to help. If you're ru
## Documentation
-Instructions for common Bundler uses can be found on the [Bundler documentation site](http://gembundler.com/v1.0/).
+Instructions for common Bundler uses can be found on the [Bundler documentation site](http://gembundler.com/v1.1/).
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).
diff --git a/README.md b/README.md
index 8a5f1a6e9c..f2a61bf1db 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![Build Status](https://secure.travis-ci.org/carlhuda/bundler.png?branch=master)](http://travis-ci.org/carlhuda/bundler)
+
# Bundler: a gem to bundle gems
Bundler is a tool that manages gem dependencies for your ruby application. It
diff --git a/Rakefile b/Rakefile
index 56aef999be..65b876586d 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
$:.unshift File.expand_path("../lib", __FILE__)
+require 'rubygems'
require 'bundler/gem_tasks'
task :release => ["man:clean", "man:build"]
@@ -18,8 +19,8 @@ end
namespace :spec do
desc "Ensure spec dependencies are installed"
task :deps do
- sh "gem list ronn | (grep 'ronn' 1> /dev/null) || gem install ronn --no-ri --no-rdoc"
- sh "gem list rspec | (grep 'rspec (2.' 1> /dev/null) || gem install rspec --no-ri --no-rdoc"
+ sh "#{Gem.ruby} -S gem list ronn | (grep 'ronn' 1> /dev/null) || #{Gem.ruby} -S gem install ronn --no-ri --no-rdoc"
+ sh "#{Gem.ruby} -S gem list rspec | (grep 'rspec (2.' 1> /dev/null) || #{Gem.ruby} -S gem install rspec --no-ri --no-rdoc"
end
end
@@ -40,7 +41,7 @@ begin
rm_rf 'tmp'
end
- desc "Run the real-world spec suite (reequires internet)"
+ desc "Run the real-world spec suite (requires internet)"
task :realworld => ["set_realworld", "spec"]
task :set_realworld do
@@ -142,7 +143,7 @@ begin
roff = "lib/bundler/man/#{basename}"
file roff => ["lib/bundler/man", ronn] do
- sh "ronn --roff --pipe #{ronn} > #{roff}"
+ sh "#{Gem.ruby} -S ronn --roff --pipe #{ronn} > #{roff}"
end
file "#{roff}.txt" => roff do
@@ -178,7 +179,7 @@ begin
desc "Install CI dependencies"
task :deps do
- sh "gem list ci_reporter | (grep 'ci_reporter' 1> /dev/null) || gem install ci_reporter --no-ri --no-rdoc"
+ sh "#{Gem.ruby} -S gem list ci_reporter | (grep 'ci_reporter' 1> /dev/null) || #{Gem.ruby} -S gem install ci_reporter --no-ri --no-rdoc"
end
task :deps => "spec:deps"
end
diff --git a/bin/bundle b/bin/bundle
index 1957812ab0..53997cf2f4 100755
--- a/bin/bundle
+++ b/bin/bundle
@@ -1,29 +1,14 @@
#!/usr/bin/env ruby
require 'bundler'
-begin
- # Check if an older version of bundler is installed
- $:.each do |path|
- if path =~ %r'/bundler-0.(\d+)' && $1.to_i < 9
- err = "Please remove Bundler 0.8 versions."
- err << "This can be done by running `gem cleanup bundler`."
- abort(err)
- end
+# Check if an older version of bundler is installed
+$:.each do |path|
+ if path =~ %r'/bundler-0.(\d+)' && $1.to_i < 9
+ err = "Please remove Bundler 0.8 versions."
+ err << "This can be done by running `gem cleanup bundler`."
+ abort(err)
end
- require 'bundler/cli'
- Bundler::CLI.start
-rescue Bundler::BundlerError => e
- Bundler.ui.error e.message
- Bundler.ui.debug e.backtrace.join("\n")
- exit e.status_code
-rescue Interrupt => e
- Bundler.ui.error "\nQuitting..."
- Bundler.ui.debug e.backtrace.join("\n")
- exit 1
-rescue SystemExit => e
- exit e.status
-rescue Exception => e
- Bundler.ui.error(
- "Unfortunately, a fatal error has occurred. Please see the Bundler \n" \
- "troubleshooting documentation at http://bit.ly/bundler-issues. Thanks! \n")
- raise e
end
+
+require 'bundler/cli'
+require 'bundler/friendly_errors'
+Bundler.with_friendly_errors { Bundler::CLI.start }
diff --git a/lib/bundler.rb b/lib/bundler.rb
index ee4d5f6971..8c325dac93 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -27,12 +27,14 @@ module Bundler
autoload :MatchPlatform, 'bundler/match_platform'
autoload :RemoteSpecification, 'bundler/remote_specification'
autoload :Resolver, 'bundler/resolver'
+ autoload :RubyVersion, 'bundler/ruby_version'
autoload :Runtime, 'bundler/runtime'
autoload :Settings, 'bundler/settings'
autoload :SharedHelpers, 'bundler/shared_helpers'
autoload :SpecSet, 'bundler/spec_set'
autoload :Source, 'bundler/source'
autoload :Specification, 'bundler/shared_helpers'
+ autoload :SystemRubyVersion, 'bundler/ruby_version'
autoload :UI, 'bundler/ui'
class BundlerError < StandardError
@@ -41,19 +43,20 @@ module Bundler
end
end
- class GemfileNotFound < BundlerError; status_code(10) ; end
- class GemNotFound < BundlerError; status_code(7) ; end
- class GemfileError < BundlerError; status_code(4) ; end
- class InstallError < BundlerError; status_code(5) ; end
- class InstallHookError < BundlerError; status_code(6) ; end
- class PathError < BundlerError; status_code(13) ; end
- class GitError < BundlerError; status_code(11) ; end
- class DeprecatedError < BundlerError; status_code(12) ; end
- class GemspecError < BundlerError; status_code(14) ; end
- class DslError < BundlerError; status_code(15) ; end
- class ProductionError < BundlerError; status_code(16) ; end
- class InvalidOption < DslError ; end
- class HTTPError < BundlerError; status_code(17) ; end
+ class GemfileNotFound < BundlerError; status_code(10) ; end
+ class GemNotFound < BundlerError; status_code(7) ; end
+ class GemfileError < BundlerError; status_code(4) ; end
+ class InstallError < BundlerError; status_code(5) ; end
+ class InstallHookError < BundlerError; status_code(6) ; end
+ class PathError < BundlerError; status_code(13) ; end
+ class GitError < BundlerError; status_code(11) ; end
+ class DeprecatedError < BundlerError; status_code(12) ; end
+ class GemspecError < BundlerError; status_code(14) ; end
+ class DslError < BundlerError; status_code(15) ; end
+ class ProductionError < BundlerError; status_code(16) ; end
+ class InvalidOption < DslError ; end
+ class HTTPError < BundlerError; status_code(17) ; end
+ class RubyVersionMismatch < BundlerError; status_code(18) ; end
WINDOWS = RbConfig::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw)!
@@ -85,10 +88,12 @@ module Bundler
@ui ||= UI.new
end
+ # Returns absolute path of where gems are installed on the filesystem.
def bundle_path
@bundle_path ||= Pathname.new(settings.path).expand_path(root)
end
+ # Returns absolute location of where binstubs are installed to.
def bin_path
@bin_path ||= begin
path = settings[:bin] || "bin"
@@ -102,6 +107,8 @@ module Bundler
# Just return if all groups are already loaded
return @setup if defined?(@setup)
+ definition.validate_ruby!
+
if groups.empty?
# Load all groups, but only once
@setup = load.setup
@@ -268,6 +275,15 @@ module Bundler
end
def load_gemspec(file)
+ @gemspec_cache ||= {}
+ key = File.expand_path(file)
+ spec = ( @gemspec_cache[key] ||= load_gemspec_uncached(file) )
+ # Protect against caching side-effected gemspecs by returning a
+ # new instance each time.
+ spec.dup if spec
+ end
+
+ def load_gemspec_uncached(file)
path = Pathname.new(file)
# Eval the gemspec from its parent directory
Dir.chdir(path.dirname.to_s) do
@@ -294,6 +310,10 @@ module Bundler
end
end
+ def clear_gemspec_cache
+ @gemspec_cache = {}
+ end
+
private
def configure_gem_home_and_path
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 665f2365c7..c5f4fc7ad6 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -99,7 +99,9 @@ module Bundler
Bundler.settings[:path] = File.expand_path(options[:path]) if options[:path]
begin
- not_installed = Bundler.definition.missing_specs
+ definition = Bundler.definition
+ definition.validate_ruby!
+ not_installed = definition.missing_specs
rescue GemNotFound, VersionConflict
Bundler.ui.error "Your Gemfile's dependencies could not be satisfied"
Bundler.ui.warn "Install missing gems with `bundle install`"
@@ -111,6 +113,9 @@ module Bundler
not_installed.each { |s| Bundler.ui.error " * #{s.name} (#{s.version})" }
Bundler.ui.warn "Install missing gems with `bundle install`"
exit 1
+ elsif !Bundler.default_lockfile.exist? && Bundler.settings[:frozen]
+ Bundler.ui.error "This bundle has been frozen, but there is no Gemfile.lock present"
+ exit 1
else
Bundler.load.lock
Bundler.ui.info "The Gemfile's dependencies are satisfied"
@@ -217,7 +222,9 @@ module Bundler
# rubygems plugins sometimes hook into the gem install process
Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
- Installer.install(Bundler.root, Bundler.definition, opts)
+ definition = Bundler.definition
+ definition.validate_ruby!
+ Installer.install(Bundler.root, definition, opts)
Bundler.load.cache if Bundler.root.join("vendor/cache").exist? && !options["no-cache"]
if Bundler.settings[:path]
@@ -256,8 +263,13 @@ module Bundler
method_option "source", :type => :array, :banner => "Update a specific source (and all gems associated with it)"
method_option "local", :type => :boolean, :banner =>
"Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
+ method_option "full-index", :type => :boolean, :banner =>
+ "Use the rubygems modern index instead of the API endpoint"
def update(*gems)
sources = Array(options[:source])
+ Bundler.ui.be_quiet! if options[:quiet]
if gems.empty? && sources.empty?
# We're doing a full update
@@ -266,10 +278,13 @@ module Bundler
Bundler.definition(:gems => gems, :sources => sources)
end
+ Bundler::Fetcher.disable_endpoint = options["full-index"]
+
opts = {"update" => true, "local" => options[:local]}
# rubygems plugins sometimes hook into the gem install process
Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
+ Bundler.definition.validate_ruby!
Installer.install Bundler.root, Bundler.definition, opts
Bundler.load.cache if Bundler.root.join("vendor/cache").exist?
clean if Bundler.settings[:clean] && Bundler.settings[:path]
@@ -285,6 +300,7 @@ module Bundler
method_option "paths", :type => :boolean,
:banner => "List the paths of all gems that are required by your Gemfile."
def show(gem_name = nil)
+ Bundler.definition.validate_ruby!
Bundler.load.lock
if gem_name
@@ -314,6 +330,7 @@ module Bundler
"Do not attempt to fetch gems remotely and use the gem cache instead"
def outdated(*gems)
sources = Array(options[:source])
+ Bundler.definition.validate_ruby!
current_specs = Bundler.load.specs
if gems.empty? && sources.empty?
@@ -362,8 +379,11 @@ module Bundler
desc "cache", "Cache all the gems to vendor/cache", :hide => true
method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
+ method_option "all", :type => :boolean, :banner => "Include all sources (including path and git)."
def cache
+ Bundler.definition.validate_ruby!
Bundler.definition.resolve_with_cache!
+ setup_cache_all
Bundler.load.cache
Bundler.settings[:no_prune] = true if options["no-prune"]
Bundler.load.lock
@@ -375,6 +395,7 @@ module Bundler
desc "package", "Locks and then caches all of the gems into vendor/cache"
method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
+ method_option "all", :type => :boolean, :banner => "Include all sources (including path and git)."
long_desc <<-D
The package command will copy the .gem files for every gem in the bundle into the
directory ./vendor/cache. If you then check that directory into your source
@@ -382,6 +403,7 @@ module Bundler
bundle without having to download any additional gems.
D
def package
+ setup_cache_all
install
# TODO: move cache contents here now that all bundles are locked
Bundler.load.cache
@@ -397,6 +419,7 @@ module Bundler
def exec(*)
ARGV.shift # remove "exec"
+ Bundler.definition.validate_ruby!
Bundler.load.setup_environment
begin
@@ -427,10 +450,17 @@ module Bundler
will show the current value, as well as any superceded values and
where they were specified.
D
- def config(name = nil, *args)
+ def config(*)
values = ARGV.dup
values.shift # remove config
- values.shift # remove the name
+
+ peek = values.shift
+
+ if peek && peek =~ /^\-\-/
+ name, scope = values.shift, $'
+ else
+ name, scope = peek, "global"
+ end
unless name
Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n"
@@ -447,29 +477,45 @@ module Bundler
return
end
- if values.empty?
- Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used"
- with_padding do
- Bundler.settings.pretty_values_for(name).each { |line| Bundler.ui.info line }
+ case scope
+ when "delete"
+ Bundler.settings.set_local(name, nil)
+ Bundler.settings.set_global(name, nil)
+ when "local", "global"
+ if values.empty?
+ Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used"
+ with_padding do
+ Bundler.settings.pretty_values_for(name).each { |line| Bundler.ui.info line }
+ end
+ return
end
- else
+
locations = Bundler.settings.locations(name)
- if local = locations[:local]
- Bundler.ui.info "Your application has set #{name} to #{local.inspect}. This will override the " \
- "system value you are currently setting"
- end
+ if scope == "global"
+ if local = locations[:local]
+ Bundler.ui.info "Your application has set #{name} to #{local.inspect}. This will override the " \
+ "global value you are currently setting"
+ end
+
+ if env = locations[:env]
+ Bundler.ui.info "You have a bundler environment variable for #{name} set to #{env.inspect}. " \
+ "This will take precedence over the global value you are setting"
+ end
- if global = locations[:global]
- Bundler.ui.info "You are replacing the current system value of #{name}, which is currently #{global}"
+ if global = locations[:global]
+ Bundler.ui.info "You are replacing the current global value of #{name}, which is currently #{global.inspect}"
+ end
end
- if env = locations[:env]
- Bundler.ui.info "You have set a bundler environment variable for #{env}. This will take precedence " \
- "over the system value you are setting"
+ if scope == "local" && local = locations[:local]
+ Bundler.ui.info "You are replacing the current local value of #{name}, which is currently #{local.inspect}"
end
- Bundler.settings.set_global(name, values.join(" "))
+ Bundler.settings.send("set_#{scope}", name, values.join(" "))
+ else
+ Bundler.ui.error "Invalid scope --#{scope} given. Please use --local or --global."
+ exit 1
end
end
@@ -583,8 +629,53 @@ module Bundler
end
end
+ desc "platform", "Displays platform compatibility information"
+ method_option "ruby", :type => :boolean, :default => false, :banner =>
+ "only display ruby related platform information"
+ def platform
+ platforms = Bundler.definition.platforms.map {|p| "* #{p}" }
+ ruby_version = Bundler.definition.ruby_version
+ output = []
+
+ if options[:ruby]
+ if ruby_version
+ output << ruby_version
+ else
+ output << "No ruby version specified"
+ end
+ else
+ output << "Your platform is: #{RUBY_PLATFORM}"
+ output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}"
+
+ if ruby_version
+ output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}"
+
+ begin
+ Bundler.definition.validate_ruby!
+ output << "Your current platform satisfies the Ruby version requirement."
+ rescue RubyVersionMismatch => e
+ output << e.message
+ end
+ else
+ output << "Your Gemfile does not specify a Ruby version requirement."
+ end
+ end
+
+ Bundler.ui.info output.join("\n\n")
+ end
+
private
+ def setup_cache_all
+ if options.key?("all")
+ Bundler.settings[:cache_all] = options[:all] || nil
+ elsif Bundler.definition.sources.any? { |s| !s.is_a?(Source::Rubygems) }
+ Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \
+ "to package them as well, please pass the --all flag. This will be the default " \
+ "on Bundler 2.0."
+ end
+ end
+
def have_groff?
!(`which groff` rescue '').empty?
end
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 874d2e1011..e215b771b1 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -5,7 +5,7 @@ module Bundler
class Definition
include GemHelpers
- attr_reader :dependencies, :platforms, :sources
+ attr_reader :dependencies, :platforms, :sources, :ruby_version
def self.build(gemfile, lockfile, unlock)
unlock ||= {}
@@ -30,13 +30,14 @@ module Bundler
specs, then we can try to resolve locally.
=end
- def initialize(lockfile, dependencies, sources, unlock)
+ def initialize(lockfile, dependencies, sources, unlock, ruby_version = "")
@unlocking = unlock == true || !unlock.empty?
@dependencies, @sources, @unlock = dependencies, sources, unlock
@remote = false
@specs = nil
@lockfile_contents = ""
+ @ruby_version = ruby_version
if lockfile && File.exists?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile)
@@ -68,28 +69,13 @@ module Bundler
@new_platform = !@platforms.include?(current_platform)
@platforms |= [current_platform]
- @path_changes = @sources.any? do |source|
- next unless source.instance_of?(Source::Path)
-
- locked = @locked_sources.find do |ls|
- ls.class == source.class && ls.path == source.path
- end
-
- if locked
- unlocking = locked.specs.any? do |spec|
- @locked_specs.any? do |locked_spec|
- locked_spec.source != locked
- end
- end
- end
-
- !locked || unlocking || source.specs != locked.specs
- end
+ @path_changes = converge_paths
eager_unlock = expand_dependencies(@unlock[:gems])
@unlock[:gems] = @locked_specs.for(eager_unlock).map { |s| s.name }
@source_changes = converge_sources
@dependency_changes = converge_dependencies
+ @local_changes = converge_locals
fixup_dependency_types!
end
@@ -174,7 +160,7 @@ module Bundler
def resolve
@resolve ||= begin
- if Bundler.settings[:frozen] || (!@unlocking && !@source_changes && !@dependency_changes && !@new_platform && !@path_changes)
+ if Bundler.settings[:frozen] || (!@unlocking && nothing_changed?)
@locked_specs
else
last_resolve = converge_locked_specs
@@ -350,8 +336,32 @@ module Bundler
raise ProductionError, msg if added.any? || deleted.any? || changed.any?
end
+ def validate_ruby!
+ return unless ruby_version
+
+ system_ruby_version = Bundler::SystemRubyVersion.new
+ if diff = ruby_version.diff(system_ruby_version)
+ problem, expected, actual = diff
+
+ msg = case problem
+ when :engine
+ "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}"
+ when :version
+ "Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
+ when :engine_version
+ "Your #{system_ruby_version.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
+ end
+
+ raise RubyVersionMismatch, msg
+ end
+ end
+
private
+ def nothing_changed?
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes
+ end
+
def pretty_dep(dep, source = false)
msg = "#{dep.name}"
msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
@@ -359,6 +369,52 @@ module Bundler
msg
end
+ # Check if the specs of the given source changed
+ # according to the locked source. A block should be
+ # in order to specify how the locked version of
+ # the source should be found.
+ def specs_changed?(source, &block)
+ locked = @locked_sources.find(&block)
+
+ if locked
+ unlocking = locked.specs.any? do |spec|
+ @locked_specs.any? do |locked_spec|
+ locked_spec.source != locked
+ end
+ end
+ end
+
+ !locked || unlocking || source.specs != locked.specs
+ end
+
+ # Get all locals and override their matching sources.
+ # Return true if any of the locals changed (for example,
+ # they point to a new revision) or depend on new specs.
+ def converge_locals
+ locals = []
+
+ Bundler.settings.local_overrides.map do |k,v|
+ spec = @dependencies.find { |s| s.name == k }
+ source = spec && spec.source
+ if source && source.respond_to?(:local_override!)
+ locals << [ source, source.local_override!(v) ]
+ end
+ end
+
+ locals.any? do |source, changed|
+ changed || specs_changed?(source) { |o| source.class === o.class && source.uri == o.uri }
+ end
+ end
+
+ def converge_paths
+ @sources.any? do |source|
+ next unless source.instance_of?(Source::Path)
+ specs_changed?(source) do |ls|
+ ls.class == source.class && ls.path == source.path
+ end
+ end
+ end
+
def converge_sources
changes = false
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index f62cf03ee9..f54b0d9ef8 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -4,7 +4,7 @@ module Bundler
class Dsl
def self.evaluate(gemfile, lockfile, unlock)
builder = new
- builder.instance_eval(Bundler.read_file(gemfile.to_s), gemfile.to_s, 1)
+ builder.eval_gemfile(gemfile)
builder.to_definition(lockfile, unlock)
rescue ScriptError, RegexpError, NameError, ArgumentError => e
e.backtrace[0] = "#{e.backtrace[0]}: #{e.message} (#{e.class})"
@@ -15,6 +15,8 @@ module Bundler
VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze
+ attr_accessor :dependencies
+
def initialize
@rubygems_source = Source::Rubygems.new
@source = nil
@@ -23,9 +25,15 @@ module Bundler
@groups = []
@platforms = []
@env = nil
+ @ruby_version = nil
end
- attr_accessor :dependencies
+ def eval_gemfile(gemfile)
+ instance_eval(Bundler.read_file(gemfile.to_s), gemfile.to_s, 1)
+ rescue SyntaxError => e
+ bt = e.message.split("\n")[1..-1]
+ raise GemfileError, ["Gemfile syntax error:", *bt].join("\n")
+ end
def gemspec(opts = nil)
path = opts && opts[:path] || '.'
@@ -59,7 +67,6 @@ module Bundler
options = Hash === args.last ? args.pop : {}
version = args || [">= 0"]
- _deprecated_options(options)
_normalize_options(name, version, options)
dep = Dependency.new(name, version, options)
@@ -138,7 +145,7 @@ module Bundler
def to_definition(lockfile, unlock)
@sources << @rubygems_source unless @sources.include?(@rubygems_source)
- Definition.new(lockfile, @dependencies, @sources, unlock)
+ Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version)
end
def group(*args, &blk)
@@ -163,19 +170,18 @@ module Bundler
@env = old
end
- # Deprecated methods
+ def ruby(ruby_version, options = {})
+ raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil?
+ raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
- def self.deprecate(name, replacement = nil)
- define_method(name) do |*|
- message = "'#{name}' has been removed from the Gemfile DSL, "
- if replacement
- message << "and has been replaced with '#{replacement}'."
- else
- message << "and is no longer supported."
- end
- message << "\nSee the README for more information on upgrading from Bundler 0.8."
- raise DeprecatedError, message
- end
+ raise GemfileError, "ruby_version must match the :engine_version for MRI" if options[:engine] == "ruby" && options[:engine_version] && ruby_version != options[:engine_version]
+ @ruby_version = RubyVersion.new(ruby_version, options[:engine], options[:engine_version])
+ end
+
+ def method_missing(name, *args)
+ location = caller[0].split(':')[0..1].join(':')
+ raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile\n" \
+ " from #{location}"
end
private
@@ -194,7 +200,8 @@ module Bundler
def _normalize_options(name, version, opts)
_normalize_hash(opts)
- invalid_keys = opts.keys - %w(group groups git github path name branch ref tag require submodules platform platforms type)
+ valid_keys = %w(group groups git github path name branch ref tag require submodules platform platforms type)
+ invalid_keys = opts.keys - valid_keys
if invalid_keys.any?
plural = invalid_keys.size > 1
message = "You passed #{invalid_keys.map{|k| ':'+k }.join(", ")} "
@@ -203,6 +210,8 @@ module Bundler
else
message << "as an option for gem '#{name}', but it is invalid."
end
+
+ message << " Valid options are: #{valid_keys.join(", ")}"
raise InvalidOption, message
end
@@ -243,7 +252,5 @@ module Bundler
opts["group"] = groups
end
- def _deprecated_options(options)
- end
end
end
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index b7cf4028bc..9121328419 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -180,12 +180,13 @@ module Bundler
name, requirement = d
dep = Gem::Dependency.new(name, requirement.split(", "))
rescue ArgumentError => e
- if e.message.include?('Illformed requirement ["#<YAML::Syck::DefaultKey')
+ if e.message.include?('Ill-formed requirement ["#<YAML::Syck::DefaultKey')
puts # we shouldn't print the error message on the "fetching info" status line
raise GemspecError, %{Unfortunately, the gem #{s[:name]} (#{s[:number]}) } +
%{has an invalid gemspec. As a result, Bundler cannot install this Gemfile. } +
%{Please ask the gem author to yank the bad version to fix this issue. For } +
- %{more information, see http://bit.ly/syck-defaultkey.}
+ %{more information, see http://bit.ly/syck-defaultkey. For a temporary } +
+ %{workaround try using the --full-index option.}
else
raise e
end
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
new file mode 100644
index 0000000000..5cd4e19d26
--- /dev/null
+++ b/lib/bundler/friendly_errors.rb
@@ -0,0 +1,22 @@
+module Bundler
+ def self.with_friendly_errors
+ begin
+ yield
+ rescue Bundler::BundlerError => e
+ Bundler.ui.error e.message
+ Bundler.ui.debug e.backtrace.join("\n")
+ exit e.status_code
+ rescue Interrupt => e
+ Bundler.ui.error "\nQuitting..."
+ Bundler.ui.debug e.backtrace.join("\n")
+ exit 1
+ rescue SystemExit => e
+ exit e.status
+ rescue Exception => e
+ Bundler.ui.error(
+ "Unfortunately, a fatal error has occurred. Please see the Bundler \n" \
+ "troubleshooting documentation at http://bit.ly/bundler-issues. Thanks! \n")
+ raise e
+ end
+ end
+end
diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb
index 2de7aeb0c2..74cd4f8538 100644
--- a/lib/bundler/gem_helper.rb
+++ b/lib/bundler/gem_helper.rb
@@ -6,16 +6,26 @@ module Bundler
class GemHelper
include Rake::DSL if defined? Rake::DSL
- def self.install_tasks(opts = {})
- dir = opts[:dir] || Dir.pwd
- self.new(dir, opts[:name]).install
+ class << self
+ # set when install'd.
+ attr_accessor :instance
+
+ def install_tasks(opts = {})
+ new(opts[:dir], opts[:name]).install
+ end
+
+ def gemspec(&block)
+ gemspec = instance.gemspec
+ block.call(gemspec) if block
+ gemspec
+ end
end
attr_reader :spec_path, :base, :gemspec
- def initialize(base, name = nil)
+ def initialize(base = nil, name = nil)
Bundler.ui = UI::Shell.new(Thor::Base.shell.new)
- @base = base
+ @base = (base ||= Dir.pwd)
gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "{,*}.gemspec")]
raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
@spec_path = gemspecs.first
@@ -37,6 +47,8 @@ module Bundler
task 'release' do
release_gem
end
+
+ GemHelper.instance = self
end
def build_gem
diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb
index 6ab23d90ef..897c9a806f 100644
--- a/lib/bundler/graph.rb
+++ b/lib/bundler/graph.rb
@@ -40,9 +40,9 @@ module Bundler
@relations[dependency.name] += child_dependencies.map(&:name).to_set
tmp += child_dependencies
- @node_options[dependency.name] = {:label => _make_label(dependency, :node)}
+ @node_options[dependency.name] = _make_label(dependency, :node)
child_dependencies.each do |c_dependency|
- @edge_options["#{dependency.name}_#{c_dependency.name}"] = {:label => _make_label(c_dependency, :edge)}
+ @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
end
end
parent_dependencies = tmp
@@ -58,8 +58,8 @@ module Bundler
relations[group.to_s].add(dependency)
@relations[group.to_s].add(dependency.name)
- @node_options[group.to_s] ||= {:label => _make_label(group, :node)}
- @edge_options["#{group}_#{dependency.name}"] = {:label => _make_label(dependency, :edge)}
+ @node_options[group.to_s] ||= _make_label(group, :node)
+ @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
end
end
@groups = relations.keys
@@ -84,7 +84,7 @@ module Bundler
else
raise ArgumentError, "2nd argument is invalid"
end
- label
+ label.nil? ? {} : { :label => label }
end
class GraphVizClient
@@ -109,7 +109,7 @@ module Bundler
def run
@groups.each do |group|
- g.add_node(
+ g.add_nodes(
group,
{:style => 'filled',
:fillcolor => '#B9B9D5',
@@ -121,11 +121,11 @@ module Bundler
@relations.each do |parent, children|
children.each do |child|
if @groups.include?(parent)
- g.add_node(child, {:style => 'filled', :fillcolor => '#B9B9D5'}.merge(@node_options[child]))
- g.add_edge(parent, child, {:constraint => false}.merge(@edge_options["#{parent}_#{child}"]))
+ g.add_nodes(child, {:style => 'filled', :fillcolor => '#B9B9D5'}.merge(@node_options[child]))
+ g.add_edges(parent, child, {:constraint => false}.merge(@edge_options["#{parent}_#{child}"]))
else
- g.add_node(child, @node_options[child])
- g.add_edge(parent, child, @edge_options["#{parent}_#{child}"])
+ g.add_nodes(child, @node_options[child])
+ g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
end
end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 790721b624..a99f0650bf 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -7,12 +7,45 @@ module Bundler
attr_accessor :post_install_messages
end
+ # Begins the installation process for Bundler.
+ # For more information see the #run method on this class.
def self.install(root, definition, options = {})
installer = new(root, definition)
installer.run(options)
installer
end
+ # Runs the install procedures for a specific Gemfile.
+ #
+ # Firstly, this method will check to see if Bundler.bundle_path exists
+ # and if not then will create it. This is usually the location of gems
+ # on the system, be it RVM or at a system path.
+ #
+ # Secondly, it checks if Bundler has been configured to be "frozen"
+ # Frozen ensures that the Gemfile and the Gemfile.lock file are matching.
+ # This stops a situation where a developer may update the Gemfile but may not run
+ # `bundle install`, which leads to the Gemfile.lock file not being correctly updated.
+ # If this file is not correctly updated then any other developer running
+ # `bundle install` will potentially not install the correct gems.
+ #
+ # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile using
+ # Bundler::Environment#dependencies. If there are no dependencies specified then
+ # Bundler returns a warning message stating so and this method returns.
+ #
+ # Fourthly, Bundler checks if the default lockfile (Gemfile.lock) exists, and if so
+ # then proceeds to set up a defintion based on the default gemfile (Gemfile) and the
+ # default lock file (Gemfile.lock). However, this is not the case if the platform is different
+ # to that which is specified in Gemfile.lock, or if there are any missing specs for the gems.
+ #
+ # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote.
+ # This then leads into the gems being installed, along with stubs for their executables,
+ # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set
+ # earlier.
+ #
+ # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time
+ # that a user runs `bundle install` they will receive any updates from this process.
+ #
+ # Finally: TODO add documentation for how the standalone process works.
def run(options)
# Create the BUNDLE_PATH directory
begin
@@ -88,7 +121,7 @@ module Bundler
# other failure, likely a native extension build failure
Bundler.ui.info ""
Bundler.ui.warn "#{e.class}: #{e.message}"
- msg = "An error occured while installing #{spec.name} (#{spec.version}),"
+ msg = "An error occurred while installing #{spec.name} (#{spec.version}),"
msg << " and Bundler cannot continue.\nMake sure that `gem install"
msg << " #{spec.name} -v '#{spec.version}'` succeeds before bundling."
Bundler.ui.debug e.backtrace.join("\n")
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
new file mode 100644
index 0000000000..57b6caaa51
--- /dev/null
+++ b/lib/bundler/ruby_version.rb
@@ -0,0 +1,94 @@
+module Bundler
+ class RubyVersion
+ attr_reader :version, :engine, :engine_version
+
+ def initialize(version, engine, engine_version)
+ # The parameters to this method must satisfy the
+ # following constraints, which are verified in
+ # the DSL:
+ #
+ # * If an engine is specified, an engine version
+ # must also be specified
+ # * If an engine version is specified, an engine
+ # must also be specified
+ # * If the engine is "ruby", the engine version
+ # must not be specified, or the engine version
+ # specified must match the version.
+
+ @version = version
+ @engine = engine || "ruby"
+ @engine_version = engine_version || version
+ end
+
+ def to_s
+ output = "ruby #{version}"
+ output << " (#{engine} #{engine_version})" unless engine == "ruby"
+
+ output
+ end
+
+ def ==(other)
+ version == other.version &&
+ engine == other.engine &&
+ engine_version == other.engine_version
+ end
+
+ # Returns a tuple of thsee things:
+ # [diff, this, other]
+ # The priority of attributes are
+ # 1. engine
+ # 2. ruby_version
+ # 3. engine_version
+ def diff(other)
+ if engine != other.engine
+ [ :engine, engine, other.engine ]
+ elsif version != other.version
+ [ :version, version, other.version ]
+ elsif engine_version != other.engine_version
+ [ :engine_version, engine_version, other.engine_version ]
+ else
+ nil
+ end
+ end
+ end
+
+ # A subclass of RubyVersion that implements version,
+ # engine and engine_version based upon the current
+ # information in the system. It can be used anywhere
+ # a RubyVersion object is expected, and can be
+ # compared with a RubyVersion object.
+ class SystemRubyVersion < RubyVersion
+ def initialize(*)
+ # override the default initialize, because
+ # we will implement version, engine and
+ # engine_version dynamically
+ end
+
+ def version
+ RUBY_VERSION
+ end
+
+ def engine
+ if defined?(RUBY_ENGINE)
+ RUBY_ENGINE
+ else
+ # not defined in ruby 1.8.7
+ "ruby"
+ end
+ end
+
+ def engine_version
+ case engine
+ when "ruby"
+ RUBY_VERSION
+ when "rbx"
+ Rubinius::VERSION
+ when "jruby"
+ JRUBY_VERSION
+ else
+ raise BundlerError, "That RUBY_ENGINE is not recognized"
+ nil
+ end
+ end
+ end
+end
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index 86153b2a93..52e3dc6e51 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -97,7 +97,7 @@ module Bundler
def cache
FileUtils.mkdir_p(cache_path) unless File.exists?(cache_path)
- Bundler.ui.info "Updating .gem files in vendor/cache"
+ Bundler.ui.info "Updating files in vendor/cache"
specs.each do |spec|
next if spec.name == 'bundler'
spec.source.cache(spec) if spec.source.respond_to?(:cache)
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index f7dc1b477c..adf018505c 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -15,6 +15,8 @@ module Bundler
set_key(key, value, @local_config, local_config_file)
end
+ alias :set_local :[]=
+
def delete(key)
@local_config.delete(key_for(key))
end
@@ -32,9 +34,19 @@ module Bundler
end
end
+ def local_overrides
+ repos = {}
+ all.each do |k|
+ if k =~ /^local\./
+ repos[$'] = self[k]
+ end
+ end
+ repos
+ end
+
def locations(key)
+ key = key_for(key)
locations = {}
-
locations[:local] = @local_config[key] if @local_config.key?(key)
locations[:env] = ENV[key] if ENV[key]
locations[:global] = @global_config[key] if @global_config.key?(key)
@@ -71,8 +83,9 @@ module Bundler
# @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"]
def path
- path = ENV[key_for(:path)] || @global_config[key_for(:path)]
- return path if path && !@local_config.key?(key_for(:path))
+ key = key_for(:path)
+ path = ENV[key] || @global_config[key]
+ return path if path && !@local_config.key?(key)
if path = self[:path]
"#{path}/#{Bundler.ruby_scope}"
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 0de9983d2c..f5d55a0d79 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -4,7 +4,7 @@ require "rubygems/installer"
require "rubygems/spec_fetcher"
require "rubygems/format"
require "digest/sha1"
-require "open3"
+require "fileutils"
module Bundler
module Source
@@ -264,12 +264,37 @@ module Bundler
Bundler.rubygems.sources = old
end
end
-
end
+
class Path
- attr_reader :path, :options
- # Kind of a hack, but needed for the lock file parser
+ class Installer < Bundler::GemInstaller
+ def initialize(spec, options = {})
+ @spec = spec
+ @bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
+ @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
+ @wrappers = options[:wrappers] || true
+ @env_shebang = options[:env_shebang] || true
+ @format_executable = options[:format_executable] || false
+ end
+
+ def generate_bin
+ return if spec.executables.nil? || spec.executables.empty?
+
+ if Bundler.requires_sudo?
+ FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
+ end
+ super
+ if Bundler.requires_sudo?
+ Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
+ spec.executables.each do |exe|
+ Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
+ end
+ end
+ end
+ end
+
+ attr_reader :path, :options
attr_writer :name
attr_accessor :version
@@ -287,8 +312,12 @@ module Bundler
@path = @path.expand_path(Bundler.root) unless @path.relative?
end
- @name = options["name"]
+ @name = options["name"]
@version = options["version"]
+
+ # Stores the original path. If at any point we move to the
+ # cached directory, we still have the original path to copy from.
+ @original_path = @path
end
def remote!
@@ -330,9 +359,46 @@ module Bundler
File.basename(path.expand_path(Bundler.root).to_s)
end
+ def install(spec)
+ Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
+ # Let's be honest, when we're working from a path, we can't
+ # really expect native extensions to work because the whole point
+ # is to just be able to modify what's in that path and go. So, let's
+ # not put ourselves through the pain of actually trying to generate
+ # the full gem.
+ Installer.new(spec).generate_bin
+ end
+
+ def cache(spec)
+ return unless Bundler.settings[:cache_all]
+ return if @original_path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
+ FileUtils.rm_rf(app_cache_path)
+ FileUtils.cp_r("#{@original_path}/.", app_cache_path)
+ end
+
+ def local_specs(*)
+ @local_specs ||= load_spec_files
+ end
+
+ def specs
+ if has_app_cache?
+ @path = app_cache_path
+ end
+ local_specs
+ end
+
+ private
+
+ def app_cache_path
+ @app_cache_path ||= Bundler.app_cache.join(name)
+ end
+
+ def has_app_cache?
+ SharedHelpers.in_bundle? && app_cache_path.exist?
+ end
+
def load_spec_files
index = Index.new
-
expanded_path = path.expand_path(Bundler.root)
if File.directory?(expanded_path)
@@ -368,61 +434,10 @@ module Bundler
index
end
- def local_specs(*)
- @local_specs ||= load_spec_files
- end
-
- class Installer < Bundler::GemInstaller
- def initialize(spec, options = {})
- @spec = spec
- @bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
- @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
- @wrappers = options[:wrappers] || true
- @env_shebang = options[:env_shebang] || true
- @format_executable = options[:format_executable] || false
- end
-
- def generate_bin
- return if spec.executables.nil? || spec.executables.empty?
-
- if Bundler.requires_sudo?
- FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
- end
- super
- if Bundler.requires_sudo?
- Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
- spec.executables.each do |exe|
- Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
- end
- end
- end
- end
-
- def install(spec)
- Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
- # Let's be honest, when we're working from a path, we can't
- # really expect native extensions to work because the whole point
- # is to just be able to modify what's in that path and go. So, let's
- # not put ourselves through the pain of actually trying to generate
- # the full gem.
- Installer.new(spec).generate_bin
- end
-
- alias specs local_specs
-
- def cache(spec)
- unless path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
- Bundler.ui.warn " * #{spec.name} at `#{path}` will not be cached."
- end
- end
-
- private
-
def relative_path
if path.to_s.match(%r{^#{Regexp.escape Bundler.root.to_s}})
return path.relative_path_from(Bundler.root)
end
-
path
end
@@ -442,7 +457,7 @@ module Bundler
gem_file = Dir.chdir(gem_dir){ Gem::Builder.new(spec).build }
- installer = Installer.new(spec, :env_shebang => false)
+ installer = Path::Installer.new(spec, :env_shebang => false)
run_hooks(:pre_install, installer)
installer.build_extensions
run_hooks(:post_build, installer)
@@ -479,20 +494,161 @@ module Bundler
end
class Git < Path
+ # The GitProxy is responsible to iteract with git repositories.
+ # All actions required by the Git source is encapsualted in this
+ # object.
+ class GitProxy
+ attr_accessor :path, :uri, :ref, :revision
+
+ def initialize(path, uri, ref, revision=nil, &allow)
+ @path = path
+ @uri = uri
+ @ref = ref
+ @revision = revision
+ @allow = allow || Proc.new { true }
+ end
+
+ def revision
+ @revision ||= allowed_in_path { git("rev-parse #{ref}").strip }
+ end
+
+ def branch
+ @branch ||= allowed_in_path do
+ git("branch") =~ /^\* (.*)$/ && $1.strip
+ end
+ end
+
+ def contains?(commit)
+ allowed_in_path do
+ result = git_null("branch --contains #{commit}")
+ $? == 0 && result =~ /^\* (.*)$/
+ end
+ end
+
+ def checkout
+ if path.exist?
+ return if has_revision_cached?
+ Bundler.ui.info "Updating #{uri}"
+ in_path do
+ git %|fetch --force --quiet --tags #{uri_escaped} "refs/heads/*:refs/heads/*"|
+ end
+ else
+ Bundler.ui.info "Fetching #{uri}"
+ FileUtils.mkdir_p(path.dirname)
+ git %|clone #{uri_escaped} "#{path}" --bare --no-hardlinks|
+ end
+ end
+
+ def copy_to(destination, submodules=false)
+ unless File.exist?(destination.join(".git"))
+ FileUtils.mkdir_p(destination.dirname)
+ FileUtils.rm_rf(destination)
+ git %|clone --no-checkout "#{path}" "#{destination}"|
+ File.chmod((0777 & ~File.umask), destination)
+ end
+
+ Dir.chdir(destination) do
+ git %|fetch --force --quiet --tags "#{path}"|
+ git "reset --hard #{@revision}"
+
+ if submodules
+ git "submodule update --init --recursive"
+ end
+ end
+ end
+
+ private
+
+ # TODO: Do not rely on /dev/null.
+ # Given that open3 is not cross platform until Ruby 1.9.3,
+ # the best solution is to pipe to /dev/null if it exists.
+ # If it doesn't, everything will work fine, but the user
+ # will get the $stderr messages as well.
+ def git_null(command)
+ if !Bundler::WINDOWS && File.exist?("/dev/null")
+ git("#{command} 2>/dev/null", false)
+ else
+ git(command, false)
+ end
+ end
+
+ def git(command, check_errors=true)
+ if allow?
+ out = %x{git #{command}}
+
+ if check_errors && $?.exitstatus != 0
+ msg = "Git error: command `git #{command}` in directory #{Dir.pwd} has failed."
+ msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist?
+ raise GitError, msg
+ end
+ out
+ else
+ raise GitError, "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " \
+ "this error message could probably be more useful. Please submit a ticket at http://github.com/carlhuda/bundler/issues " \
+ "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
+ end
+ end
+
+ def has_revision_cached?
+ return unless @revision
+ in_path { git("cat-file -e #{@revision}") }
+ true
+ rescue GitError
+ false
+ end
+
+ # Escape the URI for git commands
+ def uri_escaped
+ if Bundler::WINDOWS
+ # Windows quoting requires double quotes only, with double quotes
+ # inside the string escaped by being doubled.
+ '"' + uri.gsub('"') {|s| '""'} + '"'
+ else
+ # Bash requires single quoted strings, with the single quotes escaped
+ # by ending the string, escaping the quote, and restarting the string.
+ "'" + uri.gsub("'") {|s| "'\\''"} + "'"
+ end
+ end
+
+ def allow?
+ @allow.call
+ end
+
+ def in_path(&blk)
+ checkout unless path.exist?
+ Dir.chdir(path, &blk)
+ end
+
+ def allowed_in_path
+ if allow?
+ in_path { yield }
+ else
+ raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
+ end
+ end
+ end
+
attr_reader :uri, :ref, :options, :submodules
def initialize(options)
- super
+ @options = options
+ @glob = options["glob"] || DEFAULT_GLOB
+
+ @allow_cached = false
+ @allow_remote = false
- # stringify options that could be set as symbols
+ # Stringify options that could be set as symbols
%w(ref branch tag revision).each{|k| options[k] = options[k].to_s if options[k] }
@uri = options["uri"]
@ref = options["ref"] || options["branch"] || options["tag"] || 'master'
- @revision = options["revision"]
@submodules = options["submodules"]
+ @name = options["name"]
+ @version = options["version"]
+
@update = false
@installed = nil
+ @local = false
end
def self.from_lock(options)
@@ -522,15 +678,21 @@ module Bundler
alias == eql?
def to_s
- sref = options["ref"] ? shortref_for_display(options["ref"]) : ref
- "#{uri} (at #{sref})"
+ at = if local?
+ path
+ elsif options["ref"]
+ shortref_for_display(options["ref"])
+ else
+ ref
+ end
+ "#{uri} (at #{at})"
end
def name
File.basename(@uri, '.git')
end
- def path
+ def install_path
@install_path ||= begin
git_scope = "#{base_name}-#{shortref_for_path(revision)}"
@@ -542,32 +704,86 @@ module Bundler
end
end
+ alias :path :install_path
+
def unlock!
- @revision = nil
+ git_proxy.revision = nil
+ end
+
+ def local_override!(path)
+ return false if local?
+
+ path = Pathname.new(path)
+ path = path.expand_path(Bundler.root) unless path.relative?
+
+ unless options["branch"]
+ raise GitError, "Cannot use local override for #{name} at #{path} because " \
+ ":branch is not specified in Gemfile. Specify a branch or check " \
+ "`bundle config --delete` to remove the local override"
+ end
+
+ unless path.exist?
+ raise GitError, "Cannot use local override for #{name} because #{path} " \
+ "does not exist. Check `bundle config --delete` to remove the local override"
+ end
+
+ set_local!(path)
+
+ # Create a new git proxy without the cached revision
+ # so the Gemfile.lock always picks up the new revision.
+ @git_proxy = GitProxy.new(path, uri, ref)
+
+ if git_proxy.branch != options["branch"]
+ raise GitError, "Local override for #{name} at #{path} is using branch " \
+ "#{git_proxy.branch} but Gemfile specifies #{options["branch"]}"
+ end
+
+ changed = cached_revision && cached_revision != git_proxy.revision
+
+ if changed && !git_proxy.contains?(cached_revision)
+ raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \
+ "but the current branch in your local override for #{name} does not contain such commit. " \
+ "Please make sure your branch is up to date."
+ end
+
+ changed
end
# TODO: actually cache git specs
def specs(*)
- if allow_git_ops? && !@update
- # Start by making sure the git cache is up to date
- cache
- checkout
+ if has_app_cache? && !local?
+ set_local!(app_cache_path)
+ end
+
+ if requires_checkout? && !@update
+ git_proxy.checkout
+ git_proxy.copy_to(install_path, submodules)
@update = true
end
+
local_specs
end
def install(spec)
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
-
- unless @installed
+ if requires_checkout? && !@installed
Bundler.ui.debug " * Checking out revision: #{ref}"
- checkout if allow_git_ops?
+ git_proxy.copy_to(install_path, submodules)
@installed = true
end
generate_bin(spec)
end
+ def cache(spec)
+ return unless Bundler.settings[:cache_all]
+ return if path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
+ cached!
+ FileUtils.rm_rf(app_cache_path)
+ git_proxy.checkout if requires_checkout?
+ git_proxy.copy_to(app_cache_path, @submodules)
+ FileUtils.rm_rf(app_cache_path.join(".git"))
+ end
+
def load_spec_files
super
rescue PathError, GitError
@@ -585,23 +801,29 @@ module Bundler
end
end
end
+
private
- def git(command)
- if allow_git_ops?
- out = %x{git #{command}}
+ def set_local!(path)
+ @local = true
+ @local_specs = @git_proxy = nil
+ @cache_path = @install_path = path
+ end
+
+ def has_app_cache?
+ cached_revision && super
+ end
- if $?.exitstatus != 0
- msg = "Git error: command `git #{command}` in directory #{Dir.pwd} has failed."
- msg << "\nIf this error persists you could try removing the cache directory '#{cache_path}'" if cached?
- raise GitError, msg
- end
- out
- else
- raise GitError, "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " \
- "this error message could probably be more useful. Please submit a ticket at http://github.com/carlhuda/bundler/issues " \
- "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
- end
+ def app_cache_path
+ @app_cache_path ||= Bundler.app_cache.join("#{base_name}-#{shortref_for_path(cached_revision || revision)}")
+ end
+
+ def local?
+ @local
+ end
+
+ def requires_checkout?
+ allow_git_ops? && !local?
end
def base_name
@@ -628,82 +850,25 @@ module Bundler
Digest::SHA1.hexdigest(input)
end
- # Escape the URI for git commands
- def uri_escaped
- if Bundler::WINDOWS
- # Windows quoting requires double quotes only, with double quotes
- # inside the string escaped by being doubled.
- '"' + uri.gsub('"') {|s| '""'} + '"'
- else
- # Bash requires single quoted strings, with the single quotes escaped
- # by ending the string, escaping the quote, and restarting the string.
- "'" + uri.gsub("'") {|s| "'\\''"} + "'"
- end
- end
-
- def cache
- if cached?
- return if has_revision_cached?
- Bundler.ui.info "Updating #{uri}"
- in_cache do
- git %|fetch --force --quiet --tags #{uri_escaped} "refs/heads/*:refs/heads/*"|
- end
- else
- Bundler.ui.info "Fetching #{uri}"
- FileUtils.mkdir_p(cache_path.dirname)
- git %|clone #{uri_escaped} "#{cache_path}" --bare --no-hardlinks|
- end
- end
-
- def checkout
- unless File.exist?(path.join(".git"))
- FileUtils.mkdir_p(path.dirname)
- FileUtils.rm_rf(path)
- git %|clone --no-checkout "#{cache_path}" "#{path}"|
- File.chmod((0777 & ~File.umask), path)
- end
- Dir.chdir(path) do
- git %|fetch --force --quiet --tags "#{cache_path}"|
- git "reset --hard #{revision}"
-
- if @submodules
- git "submodule init"
- git "submodule update"
- end
- end
- end
-
- def has_revision_cached?
- return unless @revision
- in_cache { git %|cat-file -e #{@revision}| }
- true
- rescue GitError
- false
- end
-
def allow_git_ops?
@allow_remote || @allow_cached
end
+ def cached_revision
+ options["revision"]
+ end
+
def revision
- @revision ||= begin
- if allow_git_ops?
- in_cache { git("rev-parse #{ref}").strip }
- else
- raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
- end
- end
+ git_proxy.revision
end
def cached?
cache_path.exist?
end
- def in_cache(&blk)
- cache unless cached?
- Dir.chdir(cache_path, &blk)
+ def git_proxy
+ @git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision){ allow_git_ops? }
end
end
-
end
end
diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt
index 23a4b10beb..98692c5506 100644
--- a/lib/bundler/templates/newgem/README.md.tt
+++ b/lib/bundler/templates/newgem/README.md.tt
@@ -24,6 +24,6 @@ TODO: Write usage instructions here
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Added some feature'`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
diff --git a/lib/bundler/vendor/thor/parser/options.rb b/lib/bundler/vendor/thor/parser/options.rb
index 9b1d042d10..4a241a4777 100644
--- a/lib/bundler/vendor/thor/parser/options.rb
+++ b/lib/bundler/vendor/thor/parser/options.rb
@@ -1,7 +1,4 @@
class Thor
- # This is a modified version of Daniel Berger's Getopt::Long class, licensed
- # under Ruby's license.
- #
class Options < Arguments #:nodoc:
LONG_RE = /^(--\w+(?:-\w+)*)$/
SHORT_RE = /^(-[a-z])$/i
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index 2fd259aa09..4c7eb90185 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -2,5 +2,5 @@ module Bundler
# We're doing this because we might write tests that deal
# with other versions of bundler and we are unsure how to
# handle this better.
- VERSION = "1.1.4" unless defined?(::Bundler::VERSION)
+ VERSION = "1.2.0.pre.1" unless defined?(::Bundler::VERSION)
end
diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn
index cff3591e0d..46c9ac6ea7 100644
--- a/man/bundle-config.ronn
+++ b/man/bundle-config.ronn
@@ -23,6 +23,14 @@ Executing `bundle config <name> <value>` will set that configuration to the
value specified for all bundles executed as the current user. The configuration
will be stored in `~/.bundle/config`.
+Executing `bundle config --global <name> <value>` works the same as above.
+
+Executing `bundle config --local <name> <value>` will set that configuration to
+the local application. The configuration will be stored in `app/.bundle/config`.
+
+Executing `bundle config --delete <name>` will delete the configuration in both
+local and global sources.
+
## BUILD OPTIONS
You can use `bundle config` to give bundler the flags to pass to the gem
@@ -88,3 +96,35 @@ You can set them globally either via environment variables or `bundle config`,
whichever is preferable for your setup. If you use both, environment variables
will take preference over global settings.
+## LOCAL GIT REPOS
+
+Bundler also allows you to work against a git repository locally
+instead of using the remote version. This can be achieved by setting
+up a local override:
+
+ bundle config local.GEM_NAME /path/to/local/git/repository
+
+For example, in order to use a local Rack repository, a developer could call:
+
+ bundle config local.rack ~/Work/git/rack
+
+Now instead of checking out the remote git repository, the local
+override will be used. Similar to a path source, every time the local
+git repository change, changes will be automatically picked up by
+Bundler. This means a commit in the local git repo will update the
+revision in the `Gemfile.lock` to the local git repo revision. This
+requires the same attention as git submodules. Before pushing to
+the remote, you need to ensure the local override was pushed, otherwise
+you may point to a commit that only exists in your local machine.
+
+Bundler does many checks to ensure a developer won't work with
+invalid references. Particularly, we force a developer to specify
+a branch in the `Gemfile` in order to use this feature. If the branch
+specified in the `Gemfile` and the current branch in the local git
+repository do not match, Bundler will abort. This ensures that
+a developer is always working against the correct branches, avoiding
+a reference to be accidentally updated.
+
+Finally, Bundler also ensures that the current revision in the
+`Gemfile.lock` exists in the local git repository. By doing this, Bundler
+forces you to fetch the latest changes in the remotes. \ No newline at end of file
diff --git a/man/bundle-install.ronn b/man/bundle-install.ronn
index cbddd09d4a..9d169af5dd 100644
--- a/man/bundle-install.ronn
+++ b/man/bundle-install.ronn
@@ -10,6 +10,7 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
[--binstubs[=DIRECTORY]]
[--standalone[=GROUP1[ GROUP2...]]]
[--quiet]
+ [--no-cache]
## DESCRIPTION
@@ -81,6 +82,11 @@ update process below under [CONSERVATIVE UPDATING][].
`bundle` directory and installs the bundle there. It also generates
a `bundle/bundler/setup.rb` file to replace Bundler's own setup.
+* `--no-cache`:
+ Do not update the cache in `vendor/cache` with the newly bundled gems. This
+ does not remove any existing cached gems, only stops the newly bundled gems
+ from being cached during the install.
+
## DEPLOYMENT MODE
Bundler's defaults are optimized for development. To switch to
diff --git a/man/bundle-package.ronn b/man/bundle-package.ronn
index d8a709bfc9..834959bfd0 100644
--- a/man/bundle-package.ronn
+++ b/man/bundle-package.ronn
@@ -13,9 +13,9 @@ use the gems in the cache in preference to the ones on `rubygems.org`.
## GIT AND PATH GEMS
-In Bundler 1.0, the `bundle package` command only packages `.gem` files,
-not gems specified using the `:git` or `:path` options. This will likely
-change in the future.
+Since Bundler 1.2, the `bundle package` command can also package `:git` and
+`:path` dependencies besides .gem files. This needs to be explicitly enabled
+via the `--all` option. Once used, the `--all` option will be remembered.
## REMOTE FETCHING
diff --git a/man/gemfile.5.ronn b/man/gemfile.5.ronn
index 1899f173a7..53e6140247 100644
--- a/man/gemfile.5.ronn
+++ b/man/gemfile.5.ronn
@@ -25,6 +25,33 @@ might contain the gems listed in the `Gemfile`.
Each of these _source_s `MUST` be a valid Rubygems repository.
+## RUBY (#ruby)
+
+If your application requires a specific Ruby version or engine, specify your
+requirements using the `ruby` method, with the following arguments.
+All parameters are `OPTIONAL` unless otherwise specified.
+
+### VERSION (required)
+
+The version of Ruby that your application requires. If your application
+requires an alternate Ruby engine, such as JRuby or Rubinius, this should be
+the Ruby version that the engine is compatible with.
+
+ ruby "1.9.3"
+
+### ENGINE (:engine)
+
+Each application _may_ specify a Ruby engine. If an engine is specified, an
+engine version _must_ also be specified.
+
+### ENGINE VERSION (:engine_version)
+
+Each application _may_ specify a Ruby engine version. If an engine version is
+specified, an engine _must_ also be specified. If the engine is "ruby" the
+engine version specified _must_ match the Ruby version.
+
+ ruby "1.8.7", :engine => "jruby", :engine_version => "1.6.7"
+
## GEMS (#gem)
Specify gem requirements using the `gem` method, with the following arguments.
@@ -49,7 +76,6 @@ Each _gem_ `MAY` specify files that should be used when autorequiring via
`Bundler.require`. You may pass an array with multiple files, or `false` to
prevent any file from being autorequired.
- gem "sqlite3-ruby", :require => "sqlite3"
gem "redis", :require => ["redis/connection/hiredis", "redis"]
gem "webmock", :require => false
@@ -203,7 +229,7 @@ the `.gemspec`.
| |-actionpack.gemspec [actionpack gem located here]
|~activesupport
| |-activesupport.gemspec [activesupport gem located here]
- ...
+ |...
To install a gem located in a git repository, bundler changes to
the directory containing the gemspec, runs `gem build name.gemspec`
@@ -211,6 +237,20 @@ and then installs the resulting gem. The `gem build` command,
which comes standard with Rubygems, evaluates the `.gemspec` in
the context of the directory in which it is located.
+### GITHUB (:github)
+
+If the git repository you want to use is hosted on GitHub and is public, you can use the
+:github shorthand to specify just the github username and repository name (without the
+trailing ".git"), separated by a slash. If both the username and repository name are the
+same, you can omit one.
+
+ gem "rails", :github => "rails/rails"
+ gem "rails", :github => "rails"
+
+Are both equivalent to
+
+ gem "rails", :git => "git://github.com/rails/rails.git"
+
### PATH (:path)
You can specify that a gem is located in a particular location
@@ -239,7 +279,7 @@ applied to a group of gems by using block form.
platforms :ruby do
gem "ruby-debug"
- gem "sqlite3-ruby"
+ gem "sqlite3"
end
group :development do
diff --git a/spec/bundler/dsl_spec.rb b/spec/bundler/dsl_spec.rb
index 4f50c3c6bb..2bc0e40696 100644
--- a/spec/bundler/dsl_spec.rb
+++ b/spec/bundler/dsl_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
describe Bundler::Dsl do
- describe '#_normalize_options' do
- before do
- @rubygems = mock("rubygems")
- Bundler::Source::Rubygems.stub(:new){ @rubygems }
- end
+ before do
+ @rubygems = mock("rubygems")
+ Bundler::Source::Rubygems.stub(:new){ @rubygems }
+ end
+ describe '#_normalize_options' do
it "should convert :github to :git" do
subject.gem("sparks", :github => "indirect/sparks")
github_uri = "git://github.com/indirect/sparks.git"
@@ -20,6 +20,24 @@ describe Bundler::Dsl do
end
end
+ describe '#method_missing' do
+ it 'should raise an error for unknown DSL methods' do
+ Bundler.should_receive(:read_file).with("Gemfile").and_return("unknown")
+ error_msg = "Undefined local variable or method `unknown'" \
+ " for Gemfile\\s+from Gemfile:1"
+ lambda{ subject.eval_gemfile("Gemfile") }.
+ should raise_error(Bundler::GemfileError, Regexp.new(error_msg))
+ end
+ end
+
+ describe "#eval_gemfile" do
+ it "handles syntax errors with a useful message" do
+ Bundler.should_receive(:read_file).with("Gemfile").and_return("}")
+ lambda{ subject.eval_gemfile("Gemfile") }.
+ should raise_error(Bundler::GemfileError, /Gemfile syntax error/)
+ end
+ end
+
describe "syntax errors" do
it "should raise a Bundler::GemfileError" do
gemfile "gem 'foo', :path => /unquoted/string/syntax/error"
diff --git a/spec/bundler/gem_helper_spec.rb b/spec/bundler/gem_helper_spec.rb
index ad2bb32792..426760401e 100644
--- a/spec/bundler/gem_helper_spec.rb
+++ b/spec/bundler/gem_helper_spec.rb
@@ -1,4 +1,5 @@
require "spec_helper"
+require 'rake'
require 'bundler/gem_helper'
describe "Bundler::GemHelper tasks" do
@@ -61,6 +62,36 @@ describe "Bundler::GemHelper tasks" do
Bundler.ui.should be_a(Bundler::UI::Shell)
end
+ describe 'install_tasks' do
+ before(:each) do
+ @saved, Rake.application = Rake.application, Rake::Application.new
+ end
+
+ after(:each) do
+ Rake.application = @saved
+ end
+
+ it "defines Rake tasks" do
+ names = %w[build install release]
+
+ names.each { |name|
+ proc { Rake.application[name] }.should raise_error(/Don't know how to build task/)
+ }
+
+ @helper.install
+
+ names.each { |name|
+ proc { Rake.application[name] }.should_not raise_error
+ Rake.application[name].should be_instance_of Rake::Task
+ }
+ end
+
+ it "provides a way to access the gemspec object" do
+ @helper.install
+ Bundler::GemHelper.gemspec.name.should == 'test'
+ end
+ end
+
describe 'build' do
it "builds" do
mock_build_message
diff --git a/spec/cache/gems_spec.rb b/spec/cache/gems_spec.rb
index aef513b5f2..5270cd2411 100644
--- a/spec/cache/gems_spec.rb
+++ b/spec/cache/gems_spec.rb
@@ -123,7 +123,7 @@ describe "bundle cache" do
it "re-caches during install" do
cached_gem("rack-1.0.0").rmtree
bundle :install
- out.should include("Updating .gem files in vendor/cache")
+ out.should include("Updating files in vendor/cache")
cached_gem("rack-1.0.0").should exist
end
@@ -215,6 +215,15 @@ describe "bundle cache" do
out.should_not =~ /removing/i
end
+ it "does not warn about all if it doesn't have any git/path dependency" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+ bundle "cache"
+ out.should_not =~ /\-\-all/
+ end
+
it "should install gems with the name bundler in them (that aren't bundler)" do
build_gem "foo-bundler", "1.0",
:path => bundled_app('vendor/cache')
diff --git a/spec/cache/git_spec.rb b/spec/cache/git_spec.rb
index 42c3ad57b9..207af1ce26 100644
--- a/spec/cache/git_spec.rb
+++ b/spec/cache/git_spec.rb
@@ -1,5 +1,6 @@
require "spec_helper"
-describe "bundle cache with git" do
+
+describe "git base name" do
it "base_name should strip private repo uris" do
source = Bundler::Source::Git.new("uri" => "git@github.com:bundler.git")
source.send(:base_name).should == "bundler"
@@ -9,4 +10,115 @@ describe "bundle cache with git" do
source = Bundler::Source::Git.new("uri" => "//MachineName/ShareFolder")
source.send(:base_name).should == "ShareFolder"
end
- end
+end
+
+%w(cache package).each do |cmd|
+ describe "bundle #{cmd} with git" do
+ it "copies repository to vendor cache and uses it" do
+ git = build_git "foo"
+ ref = git.ref_for("master", 11)
+
+ install_gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+ bundled_app("vendor/cache/foo-1.0-#{ref}").should exist
+ bundled_app("vendor/cache/foo-1.0-#{ref}/.git").should_not exist
+
+ FileUtils.rm_rf lib_path("foo-1.0")
+ should_be_installed "foo 1.0"
+ end
+
+ it "runs twice without exploding" do
+ build_git "foo"
+
+ install_gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+ bundle "#{cmd} --all"
+
+ err.should == ""
+ FileUtils.rm_rf lib_path("foo-1.0")
+ should_be_installed "foo 1.0"
+ end
+
+ it "tracks updates" do
+ git = build_git "foo"
+ old_ref = git.ref_for("master", 11)
+
+ install_gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+
+ update_git "foo" do |s|
+ s.write "lib/foo.rb", "puts :CACHE"
+ end
+
+ ref = git.ref_for("master", 11)
+ ref.should_not == old_ref
+
+ bundle "update"
+ bundle "#{cmd} --all"
+
+ bundled_app("vendor/cache/foo-1.0-#{ref}").should exist
+
+ FileUtils.rm_rf lib_path("foo-1.0")
+ run "require 'foo'"
+ out.should == "CACHE"
+ end
+
+ it "uses the local repository to generate the cache" do
+ git = build_git "foo"
+ ref = git.ref_for("master", 11)
+
+ gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :master
+ G
+
+ bundle %|config local.foo #{lib_path('foo-1.0')}|
+ bundle "install"
+ bundle "#{cmd} --all"
+
+ bundled_app("vendor/cache/foo-invalid-#{ref}").should exist
+
+ # Updating the local still uses the local.
+ update_git "foo" do |s|
+ s.write "lib/foo.rb", "puts :LOCAL"
+ end
+
+ run "require 'foo'"
+ out.should == "LOCAL"
+ end
+
+ it "copies repository to vendor cache, including submodules" do
+ build_git "submodule", "1.0"
+
+ git = build_git "has_submodule", "1.0" do |s|
+ s.add_dependency "submodule"
+ end
+
+ Dir.chdir(lib_path('has_submodule-1.0')) do
+ `git submodule add #{lib_path('submodule-1.0')} submodule-1.0`
+ `git commit -m "submodulator"`
+ end
+
+ install_gemfile <<-G
+ git "#{lib_path('has_submodule-1.0')}", :submodules => true do
+ gem "has_submodule"
+ end
+ G
+
+ ref = git.ref_for("master", 11)
+ bundle "#{cmd} --all"
+
+ bundled_app("vendor/cache/has_submodule-1.0-#{ref}").should exist
+ bundled_app("vendor/cache/has_submodule-1.0-#{ref}/submodule-1.0").should exist
+ should_be_installed "has_submodule 1.0"
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/cache/path_spec.rb b/spec/cache/path_spec.rb
index 6a78ac3b5e..a50e5d9331 100644
--- a/spec/cache/path_spec.rb
+++ b/spec/cache/path_spec.rb
@@ -1,27 +1,103 @@
require "spec_helper"
-describe "bundle cache" do
- describe "with path sources" do
- it "is silent when the path is within the bundle" do
+%w(cache package).each do |cmd|
+ describe "bundle #{cmd} with path" do
+ it "is no-op when the path is within the bundle" do
build_lib "foo", :path => bundled_app("lib/foo")
install_gemfile <<-G
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
- bundle "cache"
- out.should == "Updating .gem files in vendor/cache"
+ bundle "#{cmd} --all"
+ bundled_app("vendor/cache/foo-1.0").should_not exist
+ should_be_installed "foo 1.0"
end
- it "warns when the path is outside of the bundle" do
+ it "copies when the path is outside the bundle " do
build_lib "foo"
install_gemfile <<-G
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
- bundle "cache"
- out.should include("foo at `#{lib_path("foo-1.0")}` will not be cached")
+ bundle "#{cmd} --all"
+ bundled_app("vendor/cache/foo-1.0").should exist
+
+ FileUtils.rm_rf lib_path("foo-1.0")
+ should_be_installed "foo 1.0"
+ end
+
+ it "updates the path on each cache" do
+ build_lib "foo"
+
+ install_gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+
+ build_lib "foo" do |s|
+ s.write "lib/foo.rb", "puts :CACHE"
+ end
+
+ bundle "#{cmd} --all"
+
+ bundled_app("vendor/cache/foo-1.0").should exist
+ FileUtils.rm_rf lib_path("foo-1.0")
+
+ run "require 'foo'"
+ out.should == "CACHE"
+ end
+
+ it "raises a warning without --all" do
+ build_lib "foo"
+
+ install_gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle cmd
+ out.should =~ /please pass the \-\-all flag/
+ bundled_app("vendor/cache/foo-1.0").should_not exist
+ end
+
+ it "stores the given flag" do
+ build_lib "foo"
+
+ install_gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+ build_lib "bar"
+
+ install_gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ gem "bar", :path => '#{lib_path("bar-1.0")}'
+ G
+
+ bundle cmd
+ bundled_app("vendor/cache/bar-1.0").should exist
+ end
+
+ it "can rewind chosen configuration" do
+ build_lib "foo"
+
+ install_gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "#{cmd} --all"
+ build_lib "baz"
+
+ gemfile <<-G
+ gem "foo", :path => '#{lib_path("foo-1.0")}'
+ gem "baz", :path => '#{lib_path("baz-1.0")}'
+ G
+
+ bundle "#{cmd} --no-all"
+ bundled_app("vendor/cache/baz-1.0").should_not exist
end
end
-end
+end \ No newline at end of file
diff --git a/spec/install/deprecated_spec.rb b/spec/install/deprecated_spec.rb
deleted file mode 100644
index fd586ec354..0000000000
--- a/spec/install/deprecated_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require "spec_helper"
-
-describe "bundle install with deprecated features" do
- before :each do
- in_app_root
- end
-
- %w().each do |deprecated|
-
- it "reports that #{deprecated} is deprecated" do
- gemfile <<-G
- #{deprecated}
- G
-
- bundle :install
- out.should =~ /'#{deprecated}' has been removed/
- out.should =~ /See the README for more information/
- end
-
- end
-
-
- %w().each do |deprecated|
-
- it "reports that :#{deprecated} is deprecated" do
- gemfile <<-G
- gem "rack", :#{deprecated} => true
- G
-
- bundle :install
- out.should =~ /Please replace :#{deprecated}|The :#{deprecated} option is no longer supported/
- end
-
- end
-
-end
diff --git a/spec/install/gems/dependency_api_spec.rb b/spec/install/gems/dependency_api_spec.rb
index 8e6fe9cb67..1a94917f45 100644
--- a/spec/install/gems/dependency_api_spec.rb
+++ b/spec/install/gems/dependency_api_spec.rb
@@ -158,15 +158,28 @@ describe "gemcutter's dependency API" do
out.should match(/Too many redirects/)
end
- it "uses the modern index when --full-index is passed" do
- gemfile <<-G
- source "#{source_uri}"
- gem "rack"
- G
+ context "when --full-index is specified" do
+ it "should use the modern index for install" do
+ gemfile <<-G
+ source "#{source_uri}"
+ gem "rack"
+ G
- bundle "install --full-index", :artifice => "endpoint"
- out.should include("Fetching source index from #{source_uri}")
- should_be_installed "rack 1.0.0"
+ bundle "install --full-index", :artifice => "endpoint"
+ out.should include("Fetching source index from #{source_uri}")
+ should_be_installed "rack 1.0.0"
+ end
+
+ it "should use the modern index for update" do
+ gemfile <<-G
+ source "#{source_uri}"
+ gem "rack"
+ G
+
+ bundle "update --full-index", :artifice => "endpoint"
+ out.should include("Fetching source index from #{source_uri}")
+ should_be_installed "rack 1.0.0"
+ end
end
it "fetches again when more dependencies are found in subsequent sources" do
diff --git a/spec/install/git_spec.rb b/spec/install/git_spec.rb
index 41a23b42f2..048880bab5 100644
--- a/spec/install/git_spec.rb
+++ b/spec/install/git_spec.rb
@@ -156,6 +156,155 @@ describe "bundle install with git sources" do
end
end
+ describe "when specifying local" do
+ it "uses the local repository instead of checking a new one out" do
+ # We don't generate it because we actually don't need it
+ # build_git "rack", "0.8"
+
+ build_git "rack", "0.8", :path => lib_path('local-rack') do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+ out.should =~ /at #{lib_path('local-rack')}/
+
+ run "require 'rack'"
+ out.should == "LOCAL"
+ end
+
+ it "chooses the local repository on runtime" do
+ build_git "rack", "0.8"
+
+ FileUtils.cp_r("#{lib_path('rack-0.8')}/.", lib_path('local-rack'))
+
+ update_git "rack", "0.8", :path => lib_path('local-rack') do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
+ end
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ run "require 'rack'"
+ out.should == "LOCAL"
+ end
+
+ it "updates specs on runtime" do
+ system_gems "nokogiri-1.4.2"
+
+ build_git "rack", "0.8"
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ lockfile0 = File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.cp_r("#{lib_path('rack-0.8')}/.", lib_path('local-rack'))
+ update_git "rack", "0.8", :path => lib_path('local-rack') do |s|
+ s.add_dependency "nokogiri", "1.4.2"
+ end
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ run "require 'rack'"
+
+ lockfile1 = File.read(bundled_app("Gemfile.lock"))
+ lockfile1.should_not == lockfile0
+ end
+
+ it "updates ref on install" do
+ build_git "rack", "0.8"
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ lockfile0 = File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.cp_r("#{lib_path('rack-0.8')}/.", lib_path('local-rack'))
+ update_git "rack", "0.8", :path => lib_path('local-rack')
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+
+ lockfile1 = File.read(bundled_app("Gemfile.lock"))
+ lockfile1.should_not == lockfile0
+ end
+
+ it "explodes if given path does not exist" do
+ build_git "rack", "0.8"
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+ out.should =~ /Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/
+ end
+
+ it "explodes if branch is not given" do
+ build_git "rack", "0.8"
+ FileUtils.cp_r("#{lib_path('rack-0.8')}/.", lib_path('local-rack'))
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+ out.should =~ /because :branch is not specified in Gemfile/
+ end
+
+ it "explodes on different branches" do
+ build_git "rack", "0.8"
+
+ FileUtils.cp_r("#{lib_path('rack-0.8')}/.", lib_path('local-rack'))
+
+ update_git "rack", "0.8", :path => lib_path('local-rack'), :branch => "another" do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
+ end
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+ out.should =~ /is using branch another but Gemfile specifies master/
+ end
+
+ it "explodes on invalid revision" do
+ build_git "rack", "0.8"
+
+ build_git "rack", "0.8", :path => lib_path('local-rack') do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
+ end
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack", :git => "#{lib_path('rack-0.8')}", :branch => "master"
+ G
+
+ bundle %|config local.rack #{lib_path('local-rack')}|
+ bundle :install
+ out.should =~ /The Gemfile lock is pointing to revision \w+/
+ end
+ end
+
describe "specified inline" do
# TODO: Figure out how to write this test so that it is not flaky depending
# on the current network situation.
@@ -573,7 +722,6 @@ describe "bundle install with git sources" do
install_gemfile <<-G
source "file://#{gem_repo1}"
-
gem "valim", "= 1.0", :git => "#{lib_path('valim')}"
G
diff --git a/spec/other/check_spec.rb b/spec/other/check_spec.rb
index 244bcce441..d6ff6d337b 100644
--- a/spec/other/check_spec.rb
+++ b/spec/other/check_spec.rb
@@ -201,6 +201,20 @@ describe "bundle check" do
end
end
+ it "fails when there's no lock file and frozen is set" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "foo"
+ G
+
+ bundle "install"
+ bundle "install --deployment"
+ FileUtils.rm(bundled_app("Gemfile.lock"))
+
+ bundle :check, :exitstatus => true
+ exitstatus.should_not eq(0)
+ end
+
context "--path" do
before do
gemfile <<-G
diff --git a/spec/other/config_spec.rb b/spec/other/config_spec.rb
index 9d65288f8a..e1b92bd49b 100644
--- a/spec/other/config_spec.rb
+++ b/spec/other/config_spec.rb
@@ -8,33 +8,131 @@ describe ".bundle/config" do
G
end
- it "can be moved with an environment variable" do
- ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s
- bundle "install --path vendor/bundle"
+ describe "BUNDLE_APP_CONFIG" do
+ it "can be moved with an environment variable" do
+ ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s
+ bundle "install --path vendor/bundle"
- bundled_app('.bundle').should_not exist
- tmp('foo/bar/config').should exist
- should_be_installed "rack 1.0.0"
+ bundled_app('.bundle').should_not exist
+ tmp('foo/bar/config').should exist
+ should_be_installed "rack 1.0.0"
+ end
+
+ it "can provide a relative path with the environment variable" do
+ FileUtils.mkdir_p bundled_app('omg')
+ Dir.chdir bundled_app('omg')
+
+ ENV['BUNDLE_APP_CONFIG'] = "../foo"
+ bundle "install --path vendor/bundle"
+
+ bundled_app(".bundle").should_not exist
+ bundled_app("../foo/config").should exist
+ should_be_installed "rack 1.0.0"
+ end
+
+ it "removes environment.rb from BUNDLE_APP_CONFIG's path" do
+ FileUtils.mkdir_p(tmp('foo/bar'))
+ ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s
+ bundle "install"
+ FileUtils.touch tmp('foo/bar/environment.rb')
+ should_be_installed "rack 1.0.0"
+ tmp('foo/bar/environment.rb').should_not exist
+ end
end
- it "can provide a relative path with the environment variable" do
- FileUtils.mkdir_p bundled_app('omg')
- Dir.chdir bundled_app('omg')
+ describe "global" do
+ before(:each) { bundle :install }
+
+ it "is the default" do
+ bundle "config foo global"
+ run "puts Bundler.settings[:foo]"
+ out.should == "global"
+ end
+
+ it "can also be set explicitly" do
+ bundle "config --global foo global"
+ run "puts Bundler.settings[:foo]"
+ out.should == "global"
+ end
+
+ it "has lower precedence than local" do
+ bundle "config --local foo local"
+
+ bundle "config --global foo global"
+ out.should =~ /Your application has set foo to "local"/
+
+ run "puts Bundler.settings[:foo]"
+ out.should == "local"
+ end
+
+ it "has lower precedence than env" do
+ begin
+ ENV["BUNDLE_FOO"] = "env"
+
+ bundle "config --global foo global"
+ out.should =~ /You have a bundler environment variable for foo set to "env"/
- ENV['BUNDLE_APP_CONFIG'] = "../foo"
- bundle "install --path vendor/bundle"
+ run "puts Bundler.settings[:foo]"
+ out.should == "env"
+ ensure
+ ENV.delete("BUNDLE_FOO")
+ end
+ end
- bundled_app(".bundle").should_not exist
- bundled_app("../foo/config").should exist
- should_be_installed "rack 1.0.0"
+ it "can be deleted" do
+ bundle "config --global foo global"
+ bundle "config --delete foo"
+
+ run "puts Bundler.settings[:foo] == nil"
+ out.should == "true"
+ end
+
+ it "warns when overriding" do
+ bundle "config --global foo previous"
+ bundle "config --global foo global"
+ out.should =~ /You are replacing the current global value of foo/
+
+ run "puts Bundler.settings[:foo]"
+ out.should == "global"
+ end
end
- it "removes environment.rb from BUNDLE_APP_CONFIG's path" do
- FileUtils.mkdir_p(tmp('foo/bar'))
- ENV['BUNDLE_APP_CONFIG'] = tmp('foo/bar').to_s
- bundle "install"
- FileUtils.touch tmp('foo/bar/environment.rb')
- should_be_installed "rack 1.0.0"
- tmp('foo/bar/environment.rb').should_not exist
+ describe "local" do
+ before(:each) { bundle :install }
+
+ it "can also be set explicitly" do
+ bundle "config --local foo local"
+ run "puts Bundler.settings[:foo]"
+ out.should == "local"
+ end
+
+ it "has higher precedence than env" do
+ begin
+ ENV["BUNDLE_FOO"] = "env"
+ bundle "config --local foo local"
+
+ run "puts Bundler.settings[:foo]"
+ out.should == "local"
+ ensure
+ ENV.delete("BUNDLE_FOO")
+ end
+ end
+
+ it "can be deleted" do
+ bundle "config --local foo local"
+ bundle "config --delete foo"
+
+ run "puts Bundler.settings[:foo] == nil"
+ out.should == "true"
+ end
+
+ it "warns when overriding" do
+ bundle "config --local foo previous"
+ bundle "config --local foo local"
+ out.should =~ /You are replacing the current local value of foo/
+
+ run "puts Bundler.settings[:foo]"
+ out.should == "local"
+ end
end
-end
+end \ No newline at end of file
diff --git a/spec/other/newgem_spec.rb b/spec/other/newgem_spec.rb
index df21035b0c..7aca310b3b 100644
--- a/spec/other/newgem_spec.rb
+++ b/spec/other/newgem_spec.rb
@@ -7,6 +7,8 @@ describe "bundle gem" do
@git_email = `git config --global user.email`.chomp
`git config --global user.email user@example.com`
bundle 'gem test-gem'
+ # reset gemspec cache for each test because of commit 3d4163a
+ Bundler.clear_gemspec_cache
end
after :each do
diff --git a/spec/other/platform_spec.rb b/spec/other/platform_spec.rb
new file mode 100644
index 0000000000..06e97cd078
--- /dev/null
+++ b/spec/other/platform_spec.rb
@@ -0,0 +1,881 @@
+require "spec_helper"
+
+describe "bundle platform" do
+ context "without flags" do
+ it "returns all the output" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+
+ #{ruby_version_correct}
+
+ gem "foo"
+ G
+
+ bundle "platform"
+ out.should == <<-G.chomp
+Your platform is: #{RUBY_PLATFORM}
+
+Your app has gems that work on these platforms:
+* ruby
+
+Your Gemfile specifies a Ruby version requirement:
+* ruby #{RUBY_VERSION}
+
+Your current platform satisfies the Ruby version requirement.
+G
+ end
+
+ it "doesn't print ruby version requirement if it isn't specified" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+
+ gem "foo"
+ G
+
+ bundle "platform"
+ out.should == <<-G.chomp
+Your platform is: #{RUBY_PLATFORM}
+
+Your app has gems that work on these platforms:
+* ruby
+
+Your Gemfile does not specify a Ruby version requirement.
+G
+ end
+
+ it "doesn't match the ruby version requirement" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+
+ #{ruby_version_incorrect}
+
+ gem "foo"
+ G
+
+ bundle "platform"
+ out.should == <<-G.chomp
+Your platform is: #{RUBY_PLATFORM}
+
+Your app has gems that work on these platforms:
+* ruby
+
+Your Gemfile specifies a Ruby version requirement:
+* ruby #{not_local_ruby_version}
+
+Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version}
+G
+ end
+ end
+
+ context "--ruby" do
+ it "returns ruby version when explicit" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.9.3", :engine => 'ruby', :engine_version => '1.9.3'
+
+ gem "foo"
+ G
+
+ bundle "platform --ruby"
+
+ out.should eq("ruby 1.9.3")
+ end
+
+ it "engine defaults to MRI" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.9.3"
+
+ gem "foo"
+ G
+
+ bundle "platform --ruby"
+
+ out.should eq("ruby 1.9.3")
+ end
+
+ it "handles jruby" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.8.7", :engine => 'jruby', :engine_version => '1.6.5'
+
+ gem "foo"
+ G
+
+ bundle "platform --ruby"
+
+ out.should eq("ruby 1.8.7 (jruby 1.6.5)")
+ end
+
+ it "handles rbx" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.8.7", :engine => 'rbx', :engine_version => '1.2.4'
+
+ gem "foo"
+ G
+
+ bundle "platform --ruby"
+
+ out.should eq("ruby 1.8.7 (rbx 1.2.4)")
+ end
+
+ it "raises an error if engine is used but engine version is not" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.8.7", :engine => 'rbx'
+
+ gem "foo"
+ G
+
+ bundle "platform", :exitstatus => true
+
+ exitstatus.should_not == 0
+ end
+
+ it "raises an error if engine_version is used but engine is not" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.8.7", :engine_version => '1.2.4'
+
+ gem "foo"
+ G
+
+ bundle "platform", :exitstatus => true
+
+ exitstatus.should_not == 0
+ end
+
+ it "raises an error if engine version doesn't match ruby version for mri" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ ruby "1.8.7", :engine => 'ruby', :engine_version => '1.2.4'
+
+ gem "foo"
+ G
+
+ bundle "platform", :exitstatus => true
+
+ exitstatus.should_not == 0
+ end
+ end
+
+ let(:ruby_version_correct) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{local_engine_version}\"" }
+ let(:ruby_version_incorrect) { "ruby \"#{not_local_ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_ruby_version}\"" }
+ let(:engine_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{RUBY_VERSION}\"" }
+ let(:engine_version_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" }
+
+ def should_be_ruby_version_incorrect(opts = {:exitstatus => true})
+ exitstatus.should eq(18) if opts[:exitstatus]
+ out.should be_include("Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version}")
+ end
+
+ def should_be_engine_incorrect(opts = {:exitstatus => true})
+ exitstatus.should eq(18) if opts[:exitstatus]
+ out.should be_include("Your Ruby engine is #{local_ruby_engine}, but your Gemfile specified #{not_local_tag}")
+ end
+
+ def should_be_engine_version_incorrect(opts = {:exitstatus => true})
+ exitstatus.should eq(18) if opts[:exitstatus]
+ out.should be_include("Your #{local_ruby_engine} version is #{local_engine_version}, but your Gemfile specified #{local_ruby_engine} #{not_local_engine_version}")
+ end
+
+ context "bundle install" do
+ it "installs fine when the ruby version matches" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{ruby_version_correct}
+ G
+
+ bundled_app('Gemfile.lock').should exist
+ end
+
+ it "doesn't install when the ruby version doesn't match" do
+ install_gemfile <<-G, :exitstatus => true
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{ruby_version_incorrect}
+ G
+
+ bundled_app('Gemfile.lock').should_not exist
+ should_be_ruby_version_incorrect
+ end
+
+ it "doesn't install when engine doesn't match" do
+ install_gemfile <<-G, :exitstatus => true
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{engine_incorrect}
+ G
+
+ bundled_app('Gemfile.lock').should_not exist
+ should_be_engine_incorrect
+ end
+
+ it "doesn't install when engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ install_gemfile <<-G, :exitstatus => true
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{engine_version_incorrect}
+ G
+
+ bundled_app('Gemfile.lock').should_not exist
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle check" do
+ it "checks fine when the ruby version matches" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{ruby_version_correct}
+ G
+
+ bundle :check, :exitstatus => true
+ exitstatus.should eq(0)
+ out.should == "The Gemfile's dependencies are satisfied"
+ end
+
+ it "fails when ruby version doesn't match" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle :check, :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails when engine doesn't match" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{engine_incorrect}
+ G
+
+ bundle :check, :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails when engine version doesn't match" do
+ simulate_ruby_engine "ruby" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+
+ #{engine_version_incorrect}
+ G
+
+ bundle :check, :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle update" do
+ before do
+ build_repo2
+
+ install_gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport"
+ gem "rack-obama"
+ G
+ end
+
+ it "updates successfully when the ruby version matches" do
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport"
+ gem "rack-obama"
+
+ #{ruby_version_correct}
+ G
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ end
+
+ bundle "update"
+ should_be_installed "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
+ end
+
+ it "fails when ruby version doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport"
+ gem "rack-obama"
+
+ #{ruby_version_incorrect}
+ G
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ end
+
+ bundle :update, :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails when ruby engine doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport"
+ gem "rack-obama"
+
+ #{engine_incorrect}
+ G
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ end
+
+ bundle :update, :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails when ruby engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport"
+ gem "rack-obama"
+
+ #{engine_version_incorrect}
+ G
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ end
+
+ bundle :update, :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle show" do
+ before do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+ G
+ end
+
+ it "prints path if ruby version is correct" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+
+ #{ruby_version_correct}
+ G
+
+ bundle "show rails"
+ out.should == default_bundle_path('gems', 'rails-2.3.2').to_s
+ end
+
+ it "fails if ruby version doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle "show rails", :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails if engine doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+
+ #{engine_incorrect}
+ G
+
+ bundle "show rails", :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails if engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+
+ #{engine_version_incorrect}
+ G
+
+ bundle "show rails", :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle cache" do
+ before do
+ gemfile <<-G
+ gem 'rack'
+ G
+
+ system_gems "rack-1.0.0"
+ end
+
+ it "copies the .gem file to vendor/cache when ruby version matches" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{ruby_version_correct}
+ G
+
+ bundle :cache
+ bundled_app("vendor/cache/rack-1.0.0.gem").should exist
+ end
+
+ it "fails if the ruby version doesn't match" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle :cache, :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails if the engine doesn't match" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{engine_incorrect}
+ G
+
+ bundle :cache, :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails if the engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{engine_version_incorrect}
+ G
+
+ bundle :cache, :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle pack" do
+ before do
+ gemfile <<-G
+ gem 'rack'
+ G
+
+ system_gems "rack-1.0.0"
+ end
+
+ it "copies the .gem file to vendor/cache when ruby version matches" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{ruby_version_correct}
+ G
+
+ bundle :pack
+ bundled_app("vendor/cache/rack-1.0.0.gem").should exist
+ end
+
+ it "fails if the ruby version doesn't match" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle :pack, :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails if the engine doesn't match" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{engine_incorrect}
+ G
+
+ bundle :pack, :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails if the engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ gem 'rack'
+
+ #{engine_version_incorrect}
+ G
+
+ bundle :pack, :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle exec" do
+ before do
+ system_gems "rack-1.0.0", "rack-0.9.1"
+ end
+
+ it "activates the correct gem when ruby version matches" do
+ gemfile <<-G
+ gem "rack", "0.9.1"
+
+ #{ruby_version_correct}
+ G
+
+ bundle "exec rackup"
+ out.should == "0.9.1"
+ end
+
+ it "fails when the ruby version doesn't match" do
+ gemfile <<-G
+ gem "rack", "0.9.1"
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle "exec rackup", :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails when the engine doesn't match" do
+ gemfile <<-G
+ gem "rack", "0.9.1"
+
+ #{engine_incorrect}
+ G
+
+ bundle "exec rackup", :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails when the engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ gem "rack", "0.9.1"
+
+ #{engine_version_incorrect}
+ G
+
+ bundle "exec rackup", :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "bundle console" do
+ before do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ gem "activesupport", :group => :test
+ gem "rack_middleware", :group => :development
+ G
+ end
+
+ it "starts IRB with the default group loaded when ruby version matches" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ gem "activesupport", :group => :test
+ gem "rack_middleware", :group => :development
+
+ #{ruby_version_correct}
+ G
+
+ bundle "console" do |input|
+ input.puts("puts RACK")
+ input.puts("exit")
+ end
+ out.should include("0.9.1")
+ end
+
+ it "fails when ruby version doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ gem "activesupport", :group => :test
+ gem "rack_middleware", :group => :development
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle "console", :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails when engine doesn't match" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ gem "activesupport", :group => :test
+ gem "rack_middleware", :group => :development
+
+ #{engine_incorrect}
+ G
+
+ bundle "console", :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails when engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ gem "activesupport", :group => :test
+ gem "rack_middleware", :group => :development
+
+ #{engine_version_incorrect}
+ G
+
+ bundle "console", :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+
+ context "Bundler.setup" do
+ before do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "yard"
+ gem "rack", :group => :test
+ G
+ end
+
+ it "makes a Gemfile.lock if setup succeeds" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "yard"
+ gem "rack"
+
+ #{ruby_version_correct}
+ G
+
+ File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.rm(bundled_app("Gemfile.lock"))
+
+ run "1"
+ bundled_app("Gemfile.lock").should exist
+ end
+
+ it "fails when ruby version doesn't match" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "yard"
+ gem "rack"
+
+ #{ruby_version_incorrect}
+ G
+
+ File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.rm(bundled_app("Gemfile.lock"))
+
+ ruby <<-R
+ require 'rubygems'
+ require 'bundler'
+
+ begin
+ Bundler.setup
+ rescue Bundler::RubyVersionMismatch => e
+ puts e.message
+ end
+ R
+
+ bundled_app("Gemfile.lock").should_not exist
+ should_be_ruby_version_incorrect(:exitstatus => false)
+ end
+
+ it "fails when engine doesn't match" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "yard"
+ gem "rack"
+
+ #{engine_incorrect}
+ G
+
+ File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.rm(bundled_app("Gemfile.lock"))
+
+ ruby <<-R
+ require 'rubygems'
+ require 'bundler'
+
+ begin
+ Bundler.setup
+ rescue Bundler::RubyVersionMismatch => e
+ puts e.message
+ end
+ R
+
+ bundled_app("Gemfile.lock").should_not exist
+ should_be_engine_incorrect(:exitstatus => false)
+ end
+
+ it "fails when engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "yard"
+ gem "rack"
+
+ #{engine_version_incorrect}
+ G
+
+ File.read(bundled_app("Gemfile.lock"))
+
+ FileUtils.rm(bundled_app("Gemfile.lock"))
+
+ ruby <<-R
+ require 'rubygems'
+ require 'bundler'
+
+ begin
+ Bundler.setup
+ rescue Bundler::RubyVersionMismatch => e
+ puts e.message
+ end
+ R
+
+ bundled_app("Gemfile.lock").should_not exist
+ should_be_engine_version_incorrect(:exitstatus => false)
+ end
+ end
+ end
+
+ context "bundle outdated" do
+ before do
+ build_repo2 do
+ build_git "foo", :path => lib_path("foo")
+ end
+
+ install_gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport", "2.3.5"
+ gem "foo", :git => "#{lib_path('foo')}"
+ G
+ end
+
+ it "returns list of outdated gems when the ruby version matches" do
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ update_git "foo", :path => lib_path("foo")
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport", "2.3.5"
+ gem "foo", :git => "#{lib_path('foo')}"
+
+ #{ruby_version_correct}
+ G
+
+ bundle "outdated"
+ out.should include("activesupport (3.0 > 2.3.5)")
+ out.should include("foo (1.0")
+ end
+
+ it "fails when the ruby version doesn't match" do
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ update_git "foo", :path => lib_path("foo")
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport", "2.3.5"
+ gem "foo", :git => "#{lib_path('foo')}"
+
+ #{ruby_version_incorrect}
+ G
+
+ bundle "outdated", :exitstatus => true
+ should_be_ruby_version_incorrect
+ end
+
+ it "fails when the engine doesn't match" do
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ update_git "foo", :path => lib_path("foo")
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport", "2.3.5"
+ gem "foo", :git => "#{lib_path('foo')}"
+
+ #{engine_incorrect}
+ G
+
+ bundle "outdated", :exitstatus => true
+ should_be_engine_incorrect
+ end
+
+ it "fails when the engine version doesn't match" do
+ simulate_ruby_engine "jruby" do
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ update_git "foo", :path => lib_path("foo")
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ gem "activesupport", "2.3.5"
+ gem "foo", :git => "#{lib_path('foo')}"
+
+ #{engine_version_incorrect}
+ G
+
+ bundle "outdated", :exitstatus => true
+ should_be_engine_version_incorrect
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb
index 664ac416e5..c458b6f6b9 100644
--- a/spec/support/helpers.rb
+++ b/spec/support/helpers.rb
@@ -60,7 +60,7 @@ module Spec
def bundle(cmd, options = {})
expect_err = options.delete(:expect_err)
exitstatus = options.delete(:exitstatus)
- options["no-color"] = true unless options.key?("no-color") || cmd.to_s[0..3] == "exec"
+ options["no-color"] = true unless options.key?("no-color") || %w(exec conf).include?(cmd.to_s[0..3])
bundle_bin = File.expand_path('../../../bin/bundle', __FILE__)
@@ -292,6 +292,17 @@ module Spec
ENV['BUNDLER_SPEC_PLATFORM'] = old if block_given?
end
+ def simulate_ruby_engine(engine, version = "1.6.0")
+ return if engine == local_ruby_engine
+
+ old, ENV['BUNDLER_SPEC_RUBY_ENGINE'] = ENV['BUNDLER_SPEC_RUBY_ENGINE'], engine
+ old_version, ENV['BUNDLER_SPEC_RUBY_ENGINE_VERSION'] = ENV['BUNDLER_SPEC_RUBY_ENGINE_VERSION'], version
+ yield if block_given?
+ ensure
+ ENV['BUNDLER_SPEC_RUBY_ENGINE'] = old if block_given?
+ ENV['BUNDLER_SPEC_RUBY_ENGINE_VERSION'] = old_version if block_given?
+ end
+
def simulate_bundler_version(version)
old, ENV['BUNDLER_SPEC_VERSION'] = ENV['BUNDLER_SPEC_VERSION'], version.to_s
yield if block_given?
diff --git a/spec/support/platforms.rb b/spec/support/platforms.rb
index 658339badc..a3114585a5 100644
--- a/spec/support/platforms.rb
+++ b/spec/support/platforms.rb
@@ -49,5 +49,38 @@ module Spec
def not_local_tag
[:ruby, :jruby].find { |tag| tag != local_tag }
end
+
+ def local_ruby_engine
+ ENV["BUNDLER_SPEC_RUBY_ENGINE"] || (defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby")
+ end
+
+ def local_engine_version
+ return ENV["BUNDLER_SPEC_RUBY_ENGINE_VERSION"] if ENV["BUNDLER_SPEC_RUBY_ENGINE_VERSION"]
+
+ case local_ruby_engine
+ when "ruby"
+ RUBY_VERSION
+ when "rbx"
+ Rubinius::VERSION
+ when "jruby"
+ JRUBY_VERSION
+ else
+ raise BundlerError, "That RUBY_ENGINE is not recognized"
+ nil
+ end
+ end
+
+ def not_local_engine_version
+ case not_local_tag
+ when :ruby
+ not_local_ruby_version
+ when :jruby
+ "1.6.1"
+ end
+ end
+
+ def not_local_ruby_version
+ "1.12"
+ end
end
end
diff --git a/spec/support/rubygems_hax/platform.rb b/spec/support/rubygems_hax/platform.rb
index 183d0801a7..a473768531 100644
--- a/spec/support/rubygems_hax/platform.rb
+++ b/spec/support/rubygems_hax/platform.rb
@@ -8,4 +8,15 @@ if ENV['BUNDLER_SPEC_VERSION']
module Bundler
VERSION = ENV['BUNDLER_SPEC_VERSION'].dup
end
-end \ No newline at end of file
+end
+
+class Object
+ if ENV['BUNDLER_SPEC_RUBY_ENGINE']
+ remove_const :RUBY_ENGINE if defined?(RUBY_ENGINE)
+ RUBY_ENGINE = ENV['BUNDLER_SPEC_RUBY_ENGINE']
+
+ if RUBY_ENGINE == "jruby"
+ JRUBY_VERSION = ENV["BUNDLER_SPEC_RUBY_ENGINE_VERSION"]
+ end
+ end
+end
diff --git a/spec/update/gems_spec.rb b/spec/update/gems_spec.rb
index 282e13d8c6..8832f276d4 100644
--- a/spec/update/gems_spec.rb
+++ b/spec/update/gems_spec.rb
@@ -33,6 +33,18 @@ describe "bundle update" do
end
end
+ describe "--quiet argument" do
+ it 'shows UI messages without --quiet argument' do
+ bundle "update"
+ out.should include("Fetching source")
+ end
+
+ it 'does not show UI messages with --quiet argument' do
+ bundle "update --quiet"
+ out.should_not include("Fetching source")
+ end
+ end
+
describe "with a top level dependency" do
it "unlocks all child dependencies that are unrelated to other locked dependencies" do
update_repo2 do