diff options
author | Andre Arko <andre@arko.net> | 2013-05-22 14:47:41 -0700 |
---|---|---|
committer | Andre Arko <andre@arko.net> | 2013-05-22 14:47:41 -0700 |
commit | 96ce07f596c29733f5414ffc7f8532e0eabea9cb (patch) | |
tree | 2ab14b92d36e0f06390f04ed3efc6989eedc37c7 | |
parent | 3d7fcaa17b2fffa831c546a10b791784eb152414 (diff) | |
parent | f7dee43156b3403c5a2b2bfda27fcd2f3486cd44 (diff) | |
download | bundler-96ce07f596c29733f5414ffc7f8532e0eabea9cb.tar.gz |
Merge branch '1-3-stable'
Conflicts:
Rakefile
spec/bundler/gem_helper_spec.rb
38 files changed, 465 insertions, 111 deletions
diff --git a/.travis.yml b/.travis.yml index 03e72cf9aa..842d42ba21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ env: # we need to know if changes to rubygems will break bundler on release - RGV=master # test the latest rubygems release with all of our supported rubies - - RGV=v2.0.0 + - RGV=v2.0.2 matrix: allow_failures: # we want to know how we're doing with head, but not fail the build diff --git a/CHANGELOG.md b/CHANGELOG.md index 963dbb1729..a6be0940e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,34 @@ -## 1.3.3 +## 1.3.5 (3 April 2013) + +Features: + + - progress indicator while resolver is running (@chief) + +Bugfixes: + + - update local overrides with orphaned revisions (@jamesferguson) + - revert to working quoting of RUBYOPT on Windows (@ogra) + - use basic auth even when SSL is not available (@jayniz) + - installing git gems without dependencies in deployment now works + +## 1.3.4 (15 March 2103) + +Bugfixes: + + - load YAML on Rubygems versions that define module YAML + - fix regression that broke --without on ruby 1.8.7 + +## 1.3.3 (13 March 2013) + +Features: + + - compatible with Rubygems 2.0.2 (higher and lower already work) + - mention skipped groups in bundle install and bundle update output (@simi) + - `gem` creates rake tasks for minitest (@coop) and rspec Bugfixes: - - use YAML.dump over {}.to_yaml for better forwards compat + - require rbconfig for standalone mode ## 1.3.2 (7 March 2013) @@ -6,7 +6,7 @@ So! You're having problems with Bundler. This file is here to help. If you're ru Instructions for common Bundler uses can be found on the [Bundler documentation site](http://gembundler.com/). -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). +Detailed information about each Bundler command, including help with common problems, can be found in the [Bundler man pages](http://gembundler.com/v1.3/man/bundle.1.html). ## Troubleshooting @@ -14,10 +14,14 @@ Detailed information about each Bundler command, including help with common prob Please open a ticket with Heroku if you're having trouble deploying. They have a professional support team who can help you resolve Heroku issues far better than the Bundler team can. If the problem that you are having turns out to be a bug in Bundler itself, Heroku support can get the exact details to us. -### Something else +### Other problems First, figure out exactly what it is that you're trying to do. Then, go to the [Bundler documentation website](http://gembundler.com) and see if we have instructions on how to do that. +Second, check [the compatibility +list](http://gembundler.com/compatibility.html), and make sure that the version of Bundler that you are +using works with the versions of Ruby and Rubygems that you are using. + If the instructions don't work, or you can't find any instructions, you can try these troubleshooting steps: # remove user-specific gems and git repos @@ -72,7 +76,7 @@ If you are using Rails 2.3, please also include: - Your environment.rb file -If you have either `rubygems-bundler` or `open_gem` installed, please try removing them and then following the troublshooting steps above before opening a new ticket. +If you have either `rubygems-bundler` or `open_gem` installed, please try removing them and then following the troubleshooting steps above before opening a new ticket. [Create a gist](https://gist.github.com) containing all of that information, then visit the [Bundler issue tracker](https://github.com/carlhuda/bundler/issues) and [create a ticket](https://github.com/carlhuda/bundler/issues/new) describing your problem and linking to your gist. @@ -1,4 +1,4 @@ -# Bundler: a gem to bundle gems [![Build Status](https://secure.travis-ci.org/carlhuda/bundler.png?branch=master)](http://travis-ci.org/carlhuda/bundler) +# Bundler: a gem to bundle gems [![Build Status](https://secure.travis-ci.org/carlhuda/bundler.png?branch=1-3-stable)](http://travis-ci.org/carlhuda/bundler) Bundler keeps ruby applications running the same code on every machine. @@ -30,7 +30,7 @@ namespace :spec do desc "Ensure spec dependencies are installed" task :deps do {"rdiscount" => "~> 1.6", "ronn" => "~> 0.7.3", "rspec" => "~> 2.13"}.each do |name, version| - sh "#{Gem.ruby} -S gem list #{name} -i -v '#{version}' || " \ + sh "#{Gem.ruby} -S gem list -i #{name} -v '#{version}' || " \ "#{Gem.ruby} -S gem install #{name} -v '#{version}' --no-ri --no-rdoc" end end @@ -88,7 +88,7 @@ begin namespace :rubygems do # Rubygems specs by version rubyopt = ENV["RUBYOPT"] - %w(master v1.3.6 v1.3.7 v1.4.2 v1.5.3 v1.6.2 v1.7.2 v1.8.25 v2.0.0).each do |rg| + %w(master v1.3.6 v1.3.7 v1.4.2 v1.5.3 v1.6.2 v1.7.2 v1.8.25 v2.0.2).each do |rg| desc "Run specs with Rubygems #{rg}" RSpec::Core::RakeTask.new(rg) do |t| t.rspec_opts = %w(-fs --color) diff --git a/bin/bundle b/bin/bundle index d2c62045bc..fc2aca105a 100755 --- a/bin/bundle +++ b/bin/bundle @@ -17,4 +17,9 @@ end require 'bundler/cli' require 'bundler/friendly_errors' -Bundler.with_friendly_errors { Bundler::CLI.start } +Bundler.with_friendly_errors { + # Set debug flag so we can rescue Thor::error's + # and set the correct exit code. + ENV["THOR_DEBUG"] = "1" + Bundler::CLI.start +} diff --git a/lib/bundler.rb b/lib/bundler.rb index 61fb7a0710..ff0f646de4 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -245,17 +245,29 @@ module Bundler end def requires_sudo? - return @requires_sudo if defined?(@checked_for_sudo) + return @requires_sudo if defined?(@requires_sudo_ran) - path = bundle_path - path = path.parent until path.exist? - sudo_present = which "sudo" - bin_dir = Pathname.new(Bundler.system_bindir) - bin_dir = bin_dir.parent until bin_dir.exist? + if settings.allow_sudo? + sudo_present = which "sudo" + end + + if sudo_present + # the bundle path and subdirectories need to be writable for Rubygems + # to be able to unpack and install gems without exploding + path = bundle_path + path = path.parent until path.exist? + + # bins are written to a different location on OS X + bin_dir = Pathname.new(Bundler.system_bindir) + bin_dir = bin_dir.parent until bin_dir.exist? + + # if any directory is not writable, we need sudo + dirs = [path, bin_dir] | Dir[path.join('*')] + sudo_needed = dirs.find{|d| !File.writable?(d) } + end - @checked_for_sudo = true - sudo_gems = !File.writable?(path) || !File.writable?(bin_dir) - @requires_sudo = settings.allow_sudo? && sudo_gems && sudo_present + @requires_sudo_ran = true + @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed end def mkdir_p(path) diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index a9fe39c8ef..69fed51be1 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -170,11 +170,10 @@ module Bundler "Use the rubygems modern index instead of the API endpoint" method_option "clean", :type => :boolean, :banner => "Run bundle clean automatically after install" - unless Bundler.rubygems.security_policies.empty? - method_option "trust-policy", :alias => "P", :type => :string, :banner => - "Gem trust policy (like gem install -P). Must be one of " + Bundler.rubygems.security_policies.keys.join('|') - end - + method_option "trust-policy", :alias => "P", :type => :string, :banner => + "Gem trust policy (like gem install -P). Must be one of " + + Bundler.rubygems.security_policies.keys.join('|') unless + Bundler.rubygems.security_policies.empty? def install opts = options.dup if opts[:without] @@ -252,26 +251,31 @@ module Bundler if Bundler.settings[:path] absolute_path = File.expand_path(Bundler.settings[:path]) relative_path = absolute_path.sub(File.expand_path('.'), '.') - Bundler.ui.confirm "Your bundle is complete! " + - "It was installed into #{relative_path}" + Bundler.ui.confirm "Your bundle is complete!" + Bundler.ui.confirm without_groups_message if Bundler.settings.without.any? + Bundler.ui.confirm "It was installed into #{relative_path}" else - Bundler.ui.confirm "Your bundle is complete! " + - "Use `bundle show [gemname]` to see where a bundled gem is installed." + Bundler.ui.confirm "Your bundle is complete!" + Bundler.ui.confirm without_groups_message if Bundler.settings.without.any? + Bundler.ui.confirm "Use `bundle show [gemname]` to see where a bundled gem is installed." end Installer.post_install_messages.to_a.each do |name, msg| - Bundler.ui.confirm "Post-install message from #{name}:\n#{msg}" + Bundler.ui.confirm "Post-install message from #{name}:" + Bundler.ui.info msg end clean if Bundler.settings[:clean] && Bundler.settings[:path] - rescue GemNotFound => e + rescue GemNotFound, VersionConflict => e if opts[:local] && Bundler.app_cache.exist? Bundler.ui.warn "Some gems seem to be missing from your vendor/cache directory." end - if Bundler.definition.no_sources? - Bundler.ui.warn "Your Gemfile has no remote sources. If you need " \ - "gems that are not already on\nyour machine, add a line like this " \ - "to your Gemfile:\n source 'https://rubygems.org'" + if Bundler.definition.rubygems_remotes.empty? + Bundler.ui.warn <<-WARN, :wrap => true + Your Gemfile has no gem server sources. If you need gems that are \ + not already on your machine, add a line like this to your Gemfile: + source 'https://rubygems.org' + WARN end raise e end @@ -317,8 +321,8 @@ module Bundler 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] - Bundler.ui.confirm "Your bundle is updated! " + - "Use `bundle show [gemname]` to see where a bundled gem is installed." + Bundler.ui.confirm "Your bundle is updated!" + Bundler.ui.confirm without_groups_message if Bundler.settings.without.any? end desc "show [GEM]", "Shows all gems that are part of the bundle, or the path to a given gem" @@ -399,7 +403,8 @@ module Bundler def outdated(*gems) sources = Array(options[:source]) Bundler.definition.validate_ruby! - current_specs = Bundler.load.specs + + current_specs = Bundler.ui.silence { Bundler.load.specs } if gems.empty? && sources.empty? # We're doing a full update @@ -488,7 +493,7 @@ module Bundler long_desc <<-D Exec runs a command, providing it access to the gems in the bundle. While using bundle exec you can require and call the bundled gems as if they were installed - into the systemwide Rubygems repository. + into the system wide Rubygems repository. D def exec(*args) Bundler.definition.validate_ruby! @@ -646,22 +651,20 @@ module Bundler method_option :requirements, :type => :boolean, :default => false, :aliases => '-r', :banner => "Set to show the version of each required dependency." method_option :format, :type => :string, :default => "png", :aliases => '-F', :banner => "This is output format option. Supported format is png, jpg, svg, dot ..." def viz + require 'graphviz' output_file = File.expand_path(options[:file]) graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format]) - - begin - graph.viz - rescue LoadError => e - Bundler.ui.error e.inspect - Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" - Bundler.ui.warn "`gem install ruby-graphviz`" - rescue StandardError => e - if e.message =~ /GraphViz not installed or dot not in PATH/ - Bundler.ui.error e.message - Bundler.ui.warn "The ruby graphviz gem requires GraphViz to be installed" - else - raise - end + graph.viz + rescue LoadError => e + Bundler.ui.error e.inspect + Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" + Bundler.ui.warn "`gem install ruby-graphviz`" + rescue StandardError => e + if e.message =~ /GraphViz not installed or dot not in PATH/ + Bundler.ui.error e.message + Bundler.ui.warn "Please install GraphViz. On a Mac with homebrew, you can run `brew install graphviz`." + else + raise end end @@ -715,7 +718,7 @@ module Bundler if options[:test] template(File.join("newgem/.travis.yml.tt"), File.join(target, ".travis.yml"), opts) end - Bundler.ui.info "Initializating git repo in #{target}" + Bundler.ui.info "Initializing git repo in #{target}" Dir.chdir(target) { `git init`; `git add .` } if options[:edit] @@ -860,5 +863,13 @@ module Bundler pager ||= 'cat' end + def without_groups_message + groups = Bundler.settings.without + group_list = [groups[0...-1].join(", "), groups[-1..-1]]. + reject{|s| s.to_s.empty? }.join(" and ") + group_str = (groups.size == 1) ? "group" : "groups" + "Gems in the #{group_str} #{group_list} were not installed." + end + end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 8c6e80c340..430182b054 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -208,8 +208,8 @@ module Bundler end end - def no_sources? - @sources.length == 1 && @sources.first.remotes.empty? + def rubygems_remotes + @sources.select{|s| s.is_a?(Source::Rubygems) }.map{|s| s.remotes }.flatten end def groups @@ -249,7 +249,7 @@ module Bundler select { |s| s.source == source }. # This needs to be sorted by full name so that # gems with the same name, but different platform - # are ordered consistantly + # are ordered consistently sort_by { |s| s.full_name }. each do |spec| next if spec.name == 'bundler' @@ -403,6 +403,7 @@ module Bundler spec = @dependencies.find { |s| s.name == k } source = spec && spec.source if source && source.respond_to?(:local_override!) + source.unlock! if @unlock[:gems].include?(spec.name) locals << [ source, source.local_override!(v) ] end end diff --git a/lib/bundler/deployment.rb b/lib/bundler/deployment.rb index 1a82514153..44a1b867b1 100644 --- a/lib/bundler/deployment.rb +++ b/lib/bundler/deployment.rb @@ -20,7 +20,7 @@ module Bundler installed to the shared/bundle path. Gems in the development and \ test group will not be installed. The install command is executed \ with the --deployment and --quiet flags. If the bundle cmd cannot \ - be found then you can override the bundle_cmd variable to specifiy \ + be found then you can override the bundle_cmd variable to specify \ which one it should use. The base path to the app is fetched from \ the :latest_release variable. Set it for custom deploy layouts. diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 1de9fb7537..d959eea6d3 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -67,7 +67,7 @@ module Bundler raise GemfileError, %{You need to specify gem names as Strings. Use 'gem "#{name.to_s}"' instead.} end - options = Hash === args.last ? args.pop : {} + options = Hash === args.last ? args.pop.dup : {} version = args _normalize_options(name, version, options) diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index 197150cf62..f5ad0347e7 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -18,7 +18,7 @@ module Bundler " is a chance you are experiencing a man-in-the-middle attack, but" \ " most likely your system doesn't have the CA certificates needed" \ " for verification. For information about OpenSSL certificates, see" \ - " bit.ly/ssl-certs. To connect without using SSL, edit your Gemfile" \ + " bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \ " sources and change 'https' to 'http'." end end @@ -68,7 +68,7 @@ module Bundler @remote_uri = remote_uri @public_uri = remote_uri.dup @public_uri.user, @public_uri.password = nil, nil # don't print these - if defined?(OpenSSL::SSL) + if defined?(Net::HTTP::Persistent) @connection = Net::HTTP::Persistent.new 'bundler', :ENV @connection.verify_mode = (Bundler.settings[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER) @@ -198,10 +198,11 @@ module Bundler begin Bundler.ui.debug "Fetching from: #{uri}" - if @connection.is_a?(Net::HTTP::Persistent) + if defined?(Net::HTTP::Persistent) response = @connection.request(uri) else req = Net::HTTP::Get.new uri.request_uri + req.basic_auth(uri.user, uri.password) if uri.user && uri.password response = @connection.request(req) end rescue OpenSSL::SSL::SSLError diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb index 91ffa34439..f5fabfec3e 100644 --- a/lib/bundler/friendly_errors.rb +++ b/lib/bundler/friendly_errors.rb @@ -5,12 +5,20 @@ module Bundler Bundler.ui.error e.message, :wrap => true Bundler.ui.trace e exit e.status_code + rescue Thor::UndefinedCommandError => e + Bundler.ui.error e.message + exit 15 + rescue Thor::Error => e + Bundler.ui.error e.message + exit 1 rescue LoadError => e raise e unless e.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ Bundler.ui.error "\nCould not load OpenSSL." - Bundler.ui.warn "You must recompile Ruby with OpenSSL support or change the sources in your" \ - "\nGemfile from 'https' to 'http'. Instructions for compiling with OpenSSL" \ - "\nusing RVM are available at rvm.io/packages/openssl." + Bundler.ui.warn <<-WARN, :wrap => true + You must recompile Ruby with OpenSSL support or change the sources in your \ + Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \ + using RVM are available at rvm.io/packages/openssl. + WARN Bundler.ui.trace e exit 1 rescue Interrupt => e @@ -21,9 +29,8 @@ module Bundler exit e.status rescue Exception => e Bundler.ui.error <<-ERR, :wrap => true - Unfortunately, a fatal error has occurred. Please see the Bundler + Unfortunately, a fatal error has occurred. Please see the Bundler \ troubleshooting documentation at http://bit.ly/bundler-issues. Thanks! - ERR raise e end diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb index dc9897beb6..9f3763db92 100644 --- a/lib/bundler/gem_helper.rb +++ b/lib/bundler/gem_helper.rb @@ -1,5 +1,4 @@ -$:.unshift File.expand_path('../vendor', __FILE__) -require 'thor' +require 'bundler/vendored_thor' unless defined?(Thor) require 'bundler' module Bundler diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb index c85f83eaa1..daf4749bef 100644 --- a/lib/bundler/graph.rb +++ b/lib/bundler/graph.rb @@ -118,7 +118,6 @@ module Bundler end def g - require 'graphviz' @g ||= ::GraphViz.digraph(@graph_name, {:concentrate => true, :normalize => true, :nodesep => 0.55}) do |g| g.edge[:weight] = 2 g.edge[:fontname] = g.node[:fontname] = 'Arial, Helvetica, SansSerif' diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index fb980caefb..7f19e94d19 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -226,6 +226,7 @@ module Bundler File.open File.join(bundler_path, "setup.rb"), "w" do |file| + file.puts "require 'rbconfig'" file.puts "# ruby 1.8.7 doesn't define RUBY_ENGINE" file.puts "ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'" file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" diff --git a/lib/bundler/psyched_yaml.rb b/lib/bundler/psyched_yaml.rb index 9c878f1e64..7ce3bb94af 100644 --- a/lib/bundler/psyched_yaml.rb +++ b/lib/bundler/psyched_yaml.rb @@ -13,7 +13,7 @@ rescue LoadError end # At least load the YAML stdlib, whatever that may be -require 'yaml' unless defined?(YAML) +require 'yaml' unless defined?(YAML.dump) module Bundler # On encountering invalid YAML, diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 25d2ec09c3..60597e32a9 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -109,7 +109,7 @@ module Bundler end end - attr_reader :errors + attr_reader :errors, :started_at, :iteration_rate, :iteration_counter # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without @@ -122,7 +122,7 @@ module Bundler # <GemBundle>,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, index, source_requirements = {}, base = []) - Bundler.ui.info "Resolving dependencies..." + Bundler.ui.info "Resolving dependencies...", false base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(index, source_requirements, base) result = catch(:success) do @@ -130,11 +130,14 @@ module Bundler raise resolver.version_conflict nil end + Bundler.ui.info "" # new line now that dots are done SpecSet.new(result) + rescue => e + Bundler.ui.info "" # new line before the error + raise e end def initialize(index, source_requirements, base) - @iteration_counter = 0 @errors = {} @stack = [] @base = base @@ -142,6 +145,8 @@ module Bundler @deps_for = {} @missing_gems = Hash.new(0) @source_requirements = source_requirements + @iteration_counter = 0 + @started_at = Time.now end def debug @@ -168,10 +173,7 @@ module Bundler # gem dependencies have been resolved. throw :success, successify(activated) if reqs.empty? - @iteration_counter += 1 - if((@iteration_counter % 10000) == 0) - Bundler.ui.info ".", false - end + indicate_progress debug { print "\e[2J\e[f" ; "==== Iterating ====\n\n" } @@ -505,5 +507,24 @@ module Bundler o end end + + private + + # Indicates progress by writing a '.' every iteration_rate time which is + # aproximately every second. iteration_rate is calculated in the first + # second of resolve running. + def indicate_progress + @iteration_counter += 1 + + if iteration_rate.nil? + if ((Time.now - started_at) % 3600).round >= 1 + @iteration_rate = iteration_counter + end + else + if ((iteration_counter % iteration_rate) == 0) + Bundler.ui.info ".", false + end + end + end end end diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index 0ba5116466..44d648bcd6 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -449,18 +449,26 @@ module Bundler Gem::Specification.find_all_by_name name end - def fetch_all_remote_specs - fetched, errors = Gem::SpecFetcher.new.available_specs(:complete) - # only raise if we don't get any specs back. - # this means we still work if prerelease_specs.4.8.gz - # don't exist but specs.4.8.gz do - if fetched.empty? && error = errors.detect {|e| e.is_a?(Gem::SourceFetchProblem) } - raise Gem::RemoteFetcher::FetchError.new(error.error, error.source) - end + def fetch_specs(source, name) + path = source + "#{name}.#{Gem.marshal_version}.gz" + string = Gem::RemoteFetcher.fetcher.fetch_path(path) + Bundler.load_marshal(string) + rescue Gem::RemoteFetcher::FetchError => e + # it's okay for prerelease to fail + raise e unless name == "prerelease_specs" + end + def fetch_all_remote_specs + # Since SpecFetcher now returns NameTuples, we just fetch directly + # and unmarshal the array ourselves. hash = {} - fetched.each do |source, tuples| - hash[source.uri] = tuples.map { |tuple| tuple.to_a } + + Gem.sources.each do |source| + source = URI.parse(source.to_s) unless source.is_a?(URI) + hash[source] = fetch_specs(source, "specs") + + pres = fetch_specs(source, "prerelease_specs") + hash[source].push(*pres) if pres && !pres.empty? end hash diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index bafffd76c4..242d919a3f 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -92,6 +92,7 @@ module Bundler def unlock! git_proxy.revision = nil + @unlocked = true end def local_override!(path) @@ -124,7 +125,7 @@ module Bundler changed = cached_revision && cached_revision != git_proxy.revision - if changed && !git_proxy.contains?(cached_revision) + if changed && !@unlocked && !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." @@ -172,8 +173,9 @@ module Bundler def load_spec_files super - rescue PathError, GitError - raise GitError, "#{to_s} is not checked out. Please run `bundle install`" + rescue PathError => e + Bundler.ui.trace e + raise GitError, "#{to_s} is not yet checked out. Run `bundle install` first." end # This is the path which is going to contain a cache diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 92f6cab1e9..0b5d264118 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -15,6 +15,7 @@ module Bundler @options = options @remotes = (options["remotes"] || []).map { |r| normalize_uri(r) } @fetchers = {} + @dependency_names = [] @allow_remote = false @allow_cached = false diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt index 29955274e0..2ecf1864b1 100644 --- a/lib/bundler/templates/newgem/Rakefile.tt +++ b/lib/bundler/templates/newgem/Rakefile.tt @@ -1 +1,16 @@ require "bundler/gem_tasks" +<% if config[:test] == 'minitest' -%> +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test" +end + +task :default => :test +<% elsif config[:test] == 'rspec' -%> +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec +<% end -%> diff --git a/lib/bundler/templates/newgem/test/test_newgem.rb.tt b/lib/bundler/templates/newgem/test/test_newgem.rb.tt index 131d0c9cfc..34cc473672 100644 --- a/lib/bundler/templates/newgem/test/test_newgem.rb.tt +++ b/lib/bundler/templates/newgem/test/test_newgem.rb.tt @@ -1,4 +1,4 @@ -require './minitest_helper' +require 'minitest_helper' class Test<%= config[:constant_name] %> < MiniTest::Unit::TestCase def test_that_it_has_a_version_number diff --git a/lib/bundler/ui.rb b/lib/bundler/ui.rb index 5de8f7538a..7ab44eb40c 100644 --- a/lib/bundler/ui.rb +++ b/lib/bundler/ui.rb @@ -20,6 +20,10 @@ module Bundler def confirm(message, newline = nil) end + def quiet? + false + end + def debug? false end @@ -110,8 +114,13 @@ module Bundler end end + def strip_leading_spaces(text) + spaces = text[/\A\s+/, 0] + spaces ? text.gsub(/#{spaces}/, '') : text + end + def word_wrap(text, line_width = @shell.terminal_width) - text.split("\n").collect do |line| + strip_leading_spaces(text).split("\n").collect do |line| line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line end * "\n" end diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 91e350485b..2e571e44d5 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.3.3" unless defined?(::Bundler::VERSION) + VERSION = "1.3.5" unless defined?(::Bundler::VERSION) end diff --git a/man/bundle-install.ronn b/man/bundle-install.ronn index 44f36a9805..1bf9066308 100644 --- a/man/bundle-install.ronn +++ b/man/bundle-install.ronn @@ -321,7 +321,7 @@ evaluates the gems currently being used to satisfy its requirements: also used to satisfy a dependency in `activemerchant`, which is not being updated * `rack ~> 1.1.0`: - not currently being used to satify another dependency + not currently being used to satisfy another dependency Because you did not explicitly ask to update `activemerchant`, you would not expect it to suddenly stop working after updating diff --git a/man/bundle.ronn b/man/bundle.ronn index 593441cd7a..c544876f81 100644 --- a/man/bundle.ronn +++ b/man/bundle.ronn @@ -44,7 +44,7 @@ We divide `bundle` subcommands into primary commands and utilities. Specify and read configuration options for bundler * `bundle help(1)`: - Displays this help page + Displays detailed help for each subcommand ## UTILITIES diff --git a/spec/bundler/cli_rspec.rb b/spec/bundler/cli_rspec.rb index baf2f9554b..e476c74498 100644 --- a/spec/bundler/cli_rspec.rb +++ b/spec/bundler/cli_rspec.rb @@ -6,4 +6,9 @@ describe 'bundle executable' do bundle '--invalid_argument', :exitstatus => true expect(exitstatus).to_not be_zero end + + it 'returns non-zero exit status when passed unrecognized task' do + bundle 'unrecognized-tast', :exitstatus => true + expect(exitstatus).to_not be_zero + end end diff --git a/spec/bundler/gem_helper_spec.rb b/spec/bundler/gem_helper_spec.rb index c18b4144ab..75f7d62c3a 100644 --- a/spec/bundler/gem_helper_spec.rb +++ b/spec/bundler/gem_helper_spec.rb @@ -177,11 +177,16 @@ describe "Bundler::GemHelper tasks" do @helper.should_receive(:rubygem_push).with(bundled_app('test/pkg/test-0.0.1.gem').to_s) - Dir.chdir(gem_repo1) { `git init --bare` } - Dir.chdir(@app) do - `git commit -a -m "another commit"` - `git tag -a -m \"Version 0.0.1\" v0.0.1` - end + Dir.chdir(gem_repo1) { + `git init --bare` + } + Dir.chdir(@app) { + `git init` + `git config user.email "you@example.com"` + `git config user.name "name"` + `git commit -a -m "another commit"` + `git tag -a -m \"Version 0.0.1\" v0.0.1` + } @helper.release_gem end diff --git a/spec/install/gems/dependency_api_spec.rb b/spec/install/gems/dependency_api_spec.rb index 0c4c46e061..c88fdcc2d2 100644 --- a/spec/install/gems/dependency_api_spec.rb +++ b/spec/install/gems/dependency_api_spec.rb @@ -99,6 +99,20 @@ describe "gemcutter's dependency API" do should_be_installed("rails 2.3.2") end + it "doesn't fail if you only have a git gem with no deps when using --deployment" do + build_git "foo" + gemfile <<-G + source "#{source_uri}" + gem 'foo', :git => "file:///#{lib_path('foo-1.0')}" + G + + bundle "install", :artifice => "endpoint" + bundle "install --deployment", :artifice => "endpoint", :exitstatus => true + + expect(exitstatus).to eq(0) + should_be_installed("foo 1.0") + end + it "falls back when the API errors out" do simulate_platform mswin diff --git a/spec/install/gems/platform_spec.rb b/spec/install/gems/platform_spec.rb index 281ebf500d..113848832f 100644 --- a/spec/install/gems/platform_spec.rb +++ b/spec/install/gems/platform_spec.rb @@ -109,7 +109,7 @@ describe "bundle install across platforms" do bundle "install --path vendor/bundle" new_version = Gem::ConfigMap[:ruby_version] == "1.8" ? "1.9.1" : "1.8" - FileUtils.mv(vendored_gems, bundled_app("vendor/bundle/#{Gem.ruby_engine}/#{new_version}")) + FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, new_version)) bundle "install --path ./vendor/bundle" expect(vendored_gems("gems/rack-1.0.0")).to exist diff --git a/spec/install/gems/simple_case_spec.rb b/spec/install/gems/simple_case_spec.rb index cd3b0c9909..4c38e77b82 100644 --- a/spec/install/gems/simple_case_spec.rb +++ b/spec/install/gems/simple_case_spec.rb @@ -291,7 +291,7 @@ describe "bundle install with gem sources" do G bundle :install, :expect_err => true - expect(out).to match(/Your Gemfile has no remote sources/i) + expect(out).to match(/Your Gemfile has no gem server sources/i) end it "creates a Gemfile.lock on a blank Gemfile" do @@ -509,7 +509,7 @@ describe "bundle install with gem sources" do G bundle :install, :quiet => true - expect(out).to match(/Your Gemfile has no remote sources/) + expect(out).to match(/Your Gemfile has no gem server sources/) end end diff --git a/spec/install/gems/sudo_spec.rb b/spec/install/gems/sudo_spec.rb index 59a4d7db51..7ff564c476 100644 --- a/spec/install/gems/sudo_spec.rb +++ b/spec/install/gems/sudo_spec.rb @@ -1,6 +1,27 @@ require "spec_helper" describe "when using sudo", :sudo => true do + describe "and BUNDLE_PATH is writable" do + context "but BUNDLE_PATH/build_info is not writable" do + before do + subdir = system_gem_path('cache') + subdir.mkpath + sudo "chmod u-w #{subdir}" + end + + it "installs" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + G + + expect(out).to_not match(/an error occurred/i) + expect(system_gem_path("cache/rack-1.0.0.gem")).to exist + should_be_installed "rack 1.0" + end + end + end + describe "and GEM_HOME is owned by root" do before :each do chown_system_gems_to_root diff --git a/spec/install/post_bundle_message_spec.rb b/spec/install/post_bundle_message_spec.rb new file mode 100644 index 0000000000..6bd4e8575d --- /dev/null +++ b/spec/install/post_bundle_message_spec.rb @@ -0,0 +1,142 @@ +require 'spec_helper' + +describe "post bundle message" do + before :each do + gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "activesupport", "2.3.5", :group => [:emo, :test] + group :test do + gem "rspec" + end + gem "rack-obama", :group => :obama + G + end + + let(:bundle_show_message) {"Use `bundle show [gemname]` to see where a bundled gem is installed."} + let(:bundle_deployment_message) {"It was installed into ./vendor"} + let(:bundle_complete_message) {"Your bundle is complete!"} + let(:bundle_updated_message) {"Your bundle is updated!"} + + describe "for fresh bundle install" do + it "without any options" do + bundle :install + expect(out).to include(bundle_show_message) + expect(out).not_to include("Gems in the group") + expect(out).to include(bundle_complete_message) + end + + it "with --without one group" do + bundle "install --without emo" + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the group emo were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without two groups" do + bundle "install --without emo test" + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without more groups" do + bundle "install --without emo obama test" + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include(bundle_complete_message) + end + + describe "with --path and" do + it "without any options" do + bundle "install --path vendor" + expect(out).to include(bundle_deployment_message) + expect(out).to_not include("Gems in the group") + expect(out).to include(bundle_complete_message) + end + + it "with --without one group" do + bundle "install --without emo --path vendor" + expect(out).to include(bundle_deployment_message) + expect(out).to include("Gems in the group emo were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without two groups" do + bundle "install --without emo test --path vendor" + expect(out).to include(bundle_deployment_message) + expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without more groups" do + bundle "install --without emo obama test --path vendor" + expect(out).to include(bundle_deployment_message) + expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include(bundle_complete_message) + end + end + end + + describe "for second bundle install run" do + it "without any options" do + 2.times { bundle :install } + expect(out).to include(bundle_show_message) + expect(out).to_not include("Gems in the groups") + expect(out).to include(bundle_complete_message) + end + + it "with --without one group" do + bundle "install --without emo" + bundle :install + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the group emo were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without two groups" do + bundle "install --without emo test" + bundle :install + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include(bundle_complete_message) + end + + it "with --without more groups" do + bundle "install --without emo obama test" + bundle :install + expect(out).to include(bundle_show_message) + expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include(bundle_complete_message) + end + end + + describe "for bundle update" do + it "without any options" do + bundle :update + expect(out).not_to include("Gems in the groups") + expect(out).to include(bundle_updated_message) + end + + it "with --without one group" do + bundle :install, :without => :emo + bundle :update + expect(out).to include("Gems in the group emo were not installed") + expect(out).to include(bundle_updated_message) + end + + it "with --without two groups" do + bundle "install --without emo test" + bundle :update + expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include(bundle_updated_message) + end + + it "with --without more groups" do + bundle "install --without emo obama test" + bundle :update + expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include(bundle_updated_message) + end + end +end diff --git a/spec/other/newgem_spec.rb b/spec/other/newgem_spec.rb index 8b45e70004..7694e94740 100644 --- a/spec/other/newgem_spec.rb +++ b/spec/other/newgem_spec.rb @@ -89,11 +89,11 @@ describe "bundle gem" do it "runs rake without problems" do system_gems ["rake-10.0.2"] - rakefile = <<-RAKEFILE + rakefile = strip_whitespace <<-RAKEFILE task :default do puts 'SUCCESS' end -RAKEFILE + RAKEFILE File.open(bundled_app("test_gem/Rakefile"), 'w') do |file| file.puts rakefile end @@ -175,7 +175,7 @@ RAKEFILE end it "requires 'minitest_helper'" do - expect(bundled_app("test_gem/test/test_test_gem.rb").read).to match(/require '.\/minitest_helper'/) + expect(bundled_app("test_gem/test/test_test_gem.rb").read).to match(/require 'minitest_helper'/) end it "creates a default test which fails" do @@ -265,11 +265,11 @@ RAKEFILE it "runs rake without problems" do system_gems ["rake-10.0.2"] - rakefile = <<-RAKEFILE + rakefile = strip_whitespace <<-RAKEFILE task :default do puts 'SUCCESS' end -RAKEFILE + RAKEFILE File.open(bundled_app("test-gem/Rakefile"), 'w') do |file| file.puts rakefile end @@ -332,6 +332,19 @@ RAKEFILE it "creates a default test which fails" do expect(bundled_app("test-gem/spec/test/gem_spec.rb").read).to match(/false.should be_true/) end + + it "creates a default rake task to run the specs" do + rakefile = strip_whitespace <<-RAKEFILE + require "bundler/gem_tasks" + require "rspec/core/rake_task" + + RSpec::Core::RakeTask.new(:spec) + + task :default => :spec + RAKEFILE + + expect(bundled_app("test-gem/Rakefile").read).to eq(rakefile) + end end context "--test parameter set to minitest" do @@ -351,12 +364,27 @@ RAKEFILE end it "requires 'minitest_helper'" do - expect(bundled_app("test-gem/test/test_test/gem.rb").read).to match(/require '.\/minitest_helper'/) + expect(bundled_app("test-gem/test/test_test/gem.rb").read).to match(/require 'minitest_helper'/) end it "creates a default test which fails" do expect(bundled_app("test-gem/test/test_test/gem.rb").read).to match(/assert false/) end + + it "creates a default rake task to run the test suite" do + rakefile = strip_whitespace <<-RAKEFILE + require "bundler/gem_tasks" + require "rake/testtask" + + Rake::TestTask.new(:test) do |t| + t.libs << "test" + end + + task :default => :test + RAKEFILE + + expect(bundled_app("test-gem/Rakefile").read).to eq(rakefile) + end end context "--test with no arguments" do diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index e38bee0f11..b52912fa75 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -314,7 +314,7 @@ describe "Bundler.setup" do it "provides a useful exception when the git repo is not checked out yet" do run "1", :expect_err => true - expect(err).to include("#{lib_path('rack-1.0.0')} (at master) is not checked out. Please run `bundle install`") + expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i) end it "does not hit the git binary if the lockfile is available and up to date" do diff --git a/spec/support/path.rb b/spec/support/path.rb index 3b981f74e1..b1d3c601f2 100644 --- a/spec/support/path.rb +++ b/spec/support/path.rb @@ -33,7 +33,7 @@ module Spec end def vendored_gems(path = nil) - bundled_app("vendor/bundle/#{Gem.ruby_engine}/#{Gem::ConfigMap[:ruby_version]}/#{path}") + bundled_app(*["vendor/bundle", Gem.ruby_engine, Gem::ConfigMap[:ruby_version], path].compact) end def cached_gem(path) diff --git a/spec/update/git_spec.rb b/spec/update/git_spec.rb index 37a0b04b25..53d6e5b275 100644 --- a/spec/update/git_spec.rb +++ b/spec/update/git_spec.rb @@ -192,5 +192,22 @@ describe "bundle update" do expect(out).to include(lib_path("foo-1.0").to_s) end + it "should not explode on invalid revision on update of gem by name" 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 "update rack" + expect(out).to include("Your bundle is updated!") + end + end end |