bundler 1.0.3 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (64) hide show
  1. data/.gitignore +10 -3
  2. data/CHANGELOG.md +31 -0
  3. data/ISSUES.md +16 -1
  4. data/LICENSE +2 -1
  5. data/Rakefile +39 -13
  6. data/bin/bundle +1 -1
  7. data/lib/bundler.rb +7 -19
  8. data/lib/bundler/capistrano.rb +0 -1
  9. data/lib/bundler/cli.rb +10 -6
  10. data/lib/bundler/definition.rb +23 -9
  11. data/lib/bundler/dependency.rb +7 -2
  12. data/lib/bundler/deployment.rb +25 -9
  13. data/lib/bundler/dsl.rb +3 -2
  14. data/lib/bundler/gem_helper.rb +25 -26
  15. data/lib/bundler/installer.rb +1 -0
  16. data/lib/bundler/resolver.rb +27 -14
  17. data/lib/bundler/rubygems_ext.rb +9 -6
  18. data/lib/bundler/runtime.rb +1 -1
  19. data/lib/bundler/setup.rb +1 -0
  20. data/lib/bundler/shared_helpers.rb +11 -4
  21. data/lib/bundler/source.rb +24 -15
  22. data/lib/bundler/ui.rb +11 -1
  23. data/lib/bundler/version.rb +1 -1
  24. data/lib/bundler/vlad.rb +1 -1
  25. data/man/bundle-exec.ronn +13 -0
  26. data/man/bundle-install.ronn +6 -3
  27. data/man/bundle.ronn +4 -1
  28. data/spec/cache/gems_spec.rb +14 -0
  29. data/spec/cache/git_spec.rb +1 -1
  30. data/spec/install/deploy_spec.rb +23 -4
  31. data/spec/install/gems/flex_spec.rb +41 -0
  32. data/spec/install/gems/groups_spec.rb +1 -1
  33. data/spec/install/gems/platform_spec.rb +4 -21
  34. data/spec/install/gems/simple_case_spec.rb +21 -14
  35. data/spec/install/gems/sudo_spec.rb +2 -2
  36. data/spec/install/gems/win32_spec.rb +1 -1
  37. data/spec/install/git_spec.rb +23 -5
  38. data/spec/install/path_spec.rb +31 -7
  39. data/spec/lock/{flex_spec.rb → lockfile_spec.rb} +33 -0
  40. data/spec/other/check_spec.rb +7 -7
  41. data/spec/other/config_spec.rb +2 -2
  42. data/spec/other/exec_spec.rb +6 -6
  43. data/spec/other/ext_spec.rb +2 -2
  44. data/spec/other/gem_helper_spec.rb +18 -6
  45. data/spec/other/help_spec.rb +1 -1
  46. data/spec/other/init_spec.rb +3 -3
  47. data/spec/quality_spec.rb +3 -0
  48. data/spec/resolver/platform_spec.rb +29 -4
  49. data/spec/runtime/load_spec.rb +47 -42
  50. data/spec/runtime/require_spec.rb +1 -1
  51. data/spec/runtime/setup_spec.rb +168 -2
  52. data/spec/spec_helper.rb +2 -1
  53. data/spec/support/builders.rb +18 -10
  54. data/spec/support/helpers.rb +7 -11
  55. data/spec/support/indexes.rb +3 -4
  56. data/spec/support/matchers.rb +1 -1
  57. data/spec/support/path.rb +1 -1
  58. data/spec/support/platforms.rb +5 -1
  59. data/spec/support/sudo.rb +1 -1
  60. data/spec/update/gems_spec.rb +26 -0
  61. data/spec/update/git_spec.rb +25 -2
  62. data/spec/update/source_spec.rb +2 -1
  63. metadata +6 -8
  64. data/spec/runtime/environment_rb_spec.rb +0 -162
data/lib/bundler/dsl.rb CHANGED
@@ -2,10 +2,10 @@ require 'bundler/dependency'
2
2
 
3
3
  module Bundler
4
4
  class Dsl
5
- def self.evaluate(gemfile)
5
+ def self.evaluate(gemfile, lockfile, unlock)
6
6
  builder = new
7
7
  builder.instance_eval(Bundler.read_file(gemfile.to_s), gemfile.to_s, 1)
8
- builder.to_definition
8
+ builder.to_definition(lockfile, unlock)
9
9
  end
10
10
 
11
11
  VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze
@@ -30,6 +30,7 @@ module Bundler
30
30
  case gemspecs.size
31
31
  when 1
32
32
  spec = Gem::Specification.load(gemspecs.first)
33
+ raise InvalidOption, "There was an error loading the gemspec at #{gemspecs.first}." unless spec
33
34
  gem spec.name, :path => path
34
35
  spec.runtime_dependencies.each do |dep|
35
36
  gem dep.name, *dep.requirement.as_list
@@ -1,19 +1,18 @@
1
1
  $:.unshift File.expand_path('../vendor', __FILE__)
2
- require 'open3'
3
2
  require 'thor'
4
3
  require 'bundler'
5
4
 
6
5
  module Bundler
7
6
  class GemHelper
8
7
  def self.install_tasks(opts = nil)
9
- dir = caller.find{|c| /Rakefile:/}[/^(.*?)\/Rakefile:/, 1]
8
+ dir = File.dirname(Rake.application.rakefile_location)
10
9
  self.new(dir, opts && opts[:name]).install
11
10
  end
12
11
 
13
12
  attr_reader :spec_path, :base, :gemspec
14
13
 
15
14
  def initialize(base, name = nil)
16
- Bundler.ui = UI::Shell.new(Thor::Shell::Color.new)
15
+ Bundler.ui = UI::Shell.new(Thor::Base.shell.new)
17
16
  @base = base
18
17
  gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "*.gemspec")]
19
18
  raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
@@ -40,8 +39,8 @@ module Bundler
40
39
 
41
40
  def build_gem
42
41
  file_name = nil
43
- sh("gem build #{spec_path}") { |out, err|
44
- raise err if !out[/Successfully/]
42
+ sh("gem build #{spec_path}") { |out, code|
43
+ raise out unless out[/Successfully/]
45
44
  file_name = File.basename(built_gem_path)
46
45
  FileUtils.mkdir_p(File.join(base, 'pkg'))
47
46
  FileUtils.mv(built_gem_path, 'pkg')
@@ -52,8 +51,8 @@ module Bundler
52
51
 
53
52
  def install_gem
54
53
  built_gem_path = build_gem
55
- out, err, code = sh_with_code("gem install #{built_gem_path}")
56
- raise err if err[/ERROR/]
54
+ out, code = sh_with_code("gem install #{built_gem_path}")
55
+ raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/]
57
56
  Bundler.ui.confirm "#{name} (#{version}) installed"
58
57
  end
59
58
 
@@ -69,7 +68,8 @@ module Bundler
69
68
 
70
69
  protected
71
70
  def rubygem_push(path)
72
- sh("gem push #{path}")
71
+ out, status = sh("gem push #{path}")
72
+ raise "Gem push failed due to lack of RubyGems.org credentials." if out[/Enter your RubyGems.org credentials/]
73
73
  Bundler.ui.confirm "Pushed #{name} #{version} to rubygems.org"
74
74
  end
75
75
 
@@ -84,8 +84,9 @@ module Bundler
84
84
  end
85
85
 
86
86
  def perform_git_push(options = '')
87
- out, err, code = sh_with_code "git push --quiet#{options}"
88
- raise err unless err == ''
87
+ cmd = "git push #{options}"
88
+ out, code = sh_with_code(cmd)
89
+ raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0
89
90
  end
90
91
 
91
92
  def guard_already_tagged
@@ -99,23 +100,20 @@ module Bundler
99
100
  end
100
101
 
101
102
  def clean?
102
- sh("git ls-files -dm").split("\n").size.zero?
103
+ out, code = sh_with_code("git diff --exit-code")
104
+ code == 0
103
105
  end
104
106
 
105
107
  def tag_version
106
- sh "git tag -am 'Version #{version}' #{version_tag}"
107
- Bundler.ui.confirm "Tagged #{tagged_sha} with #{version_tag}"
108
+ sh "git tag -a -m \"Version #{version}\" #{version_tag}"
109
+ Bundler.ui.confirm "Tagged #{version_tag}"
108
110
  yield if block_given?
109
111
  rescue
110
- Bundler.ui.error "Untagged #{tagged_sha} with #{version_tag} due to error"
111
- sh "git tag -d #{version_tag}"
112
+ Bundler.ui.error "Untagged #{version_tag} due to error"
113
+ sh_with_code "git tag -d #{version_tag}"
112
114
  raise
113
115
  end
114
116
 
115
- def tagged_sha
116
- sh("git show-ref --tags #{version_tag}").split(' ').first[0, 8]
117
- end
118
-
119
117
  def version
120
118
  gemspec.version
121
119
  end
@@ -129,20 +127,21 @@ module Bundler
129
127
  end
130
128
 
131
129
  def sh(cmd, &block)
132
- out, err, code = sh_with_code(cmd, &block)
133
- code == 0 ? out : raise(out.empty? ? err : out)
130
+ out, code = sh_with_code(cmd, &block)
131
+ code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out)
134
132
  end
135
133
 
136
134
  def sh_with_code(cmd, &block)
137
- outbuf, errbuf = '', ''
135
+ cmd << " 2>&1"
136
+ outbuf = ''
137
+ Bundler.ui.debug(cmd)
138
138
  Dir.chdir(base) {
139
- stdin, stdout, stderr = *Open3.popen3(cmd)
139
+ outbuf = `#{cmd}`
140
140
  if $? == 0
141
- outbuf, errbuf = stdout.read, stderr.read
142
- block.call(outbuf, errbuf) if block
141
+ block.call(outbuf) if block
143
142
  end
144
143
  }
145
- [outbuf, errbuf, $?]
144
+ [outbuf, $?]
146
145
  end
147
146
  end
148
147
  end
@@ -53,6 +53,7 @@ module Bundler
53
53
  old_args = Gem::Command.build_args
54
54
  Gem::Command.build_args = [Bundler.settings["build.#{spec.name}"]]
55
55
  spec.source.install(spec)
56
+ Bundler.ui.debug "from #{spec.loaded_from} "
56
57
  ensure
57
58
  Gem::Command.build_args = old_args
58
59
  end
@@ -21,10 +21,7 @@ end
21
21
 
22
22
  module Bundler
23
23
  class Resolver
24
- ALL = [ Gem::Platform::RUBY,
25
- Gem::Platform::JAVA,
26
- Gem::Platform::MSWIN,
27
- Gem::Platform::MING]
24
+ ALL = Bundler::Dependency::PLATFORM_MAP.values.uniq.freeze
28
25
 
29
26
  class SpecGroup < Array
30
27
  include GemHelpers
@@ -124,9 +121,9 @@ module Bundler
124
121
  # ==== Returns
125
122
  # <GemBundle>,nil:: If the list of dependencies can be resolved, a
126
123
  # collection of gemspecs is returned. Otherwise, nil is returned.
127
- def self.resolve(requirements, index, source_requirements = {}, base = [])
124
+ def self.resolve(requirements, index, source_requirements = {}, base = [], sort = true)
128
125
  base = SpecSet.new(base) unless base.is_a?(SpecSet)
129
- resolver = new(index, source_requirements, base)
126
+ resolver = new(index, source_requirements, base, sort)
130
127
  result = catch(:success) do
131
128
  resolver.start(requirements)
132
129
  raise resolver.version_conflict
@@ -135,13 +132,14 @@ module Bundler
135
132
  SpecSet.new(result)
136
133
  end
137
134
 
138
- def initialize(index, source_requirements, base)
135
+ def initialize(index, source_requirements, base, sort)
139
136
  @errors = {}
140
137
  @stack = []
141
138
  @base = base
142
139
  @index = index
143
140
  @missing_gems = Hash.new(0)
144
141
  @source_requirements = source_requirements
142
+ @sort = sort
145
143
  end
146
144
 
147
145
  def debug
@@ -174,12 +172,14 @@ module Bundler
174
172
  # 1) Is this gem already activated?
175
173
  # 2) Do the version requirements include prereleased gems?
176
174
  # 3) Sort by number of gems available in the source.
175
+ # This is a pretty expensive operation, so we skip it when the bundle is
176
+ # locked and sorting isn't necessary.
177
177
  reqs = reqs.sort_by do |a|
178
178
  [ activated[a.name] ? 0 : 1,
179
179
  a.requirement.prerelease? ? 0 : 1,
180
180
  @errors[a.name] ? 0 : 1,
181
181
  activated[a.name] ? 0 : search(a).size ]
182
- end
182
+ end if @sort
183
183
 
184
184
  debug { "Activated:\n" + activated.values.map { |a| " #{a.name} (#{a.version})" }.join("\n") }
185
185
  debug { "Requirements:\n" + reqs.map { |r| " #{r.name} (#{r.requirement})"}.join("\n") }
@@ -198,8 +198,9 @@ module Bundler
198
198
  # Force the current
199
199
  if current.name == 'bundler' && !existing
200
200
  existing = search(DepProxy.new(Gem::Dependency.new('bundler', VERSION), Gem::Platform::RUBY)).first
201
- activated['bundler'] = existing
202
201
  raise GemNotFound, %Q{Bundler could not find gem "bundler" (#{VERSION})} unless existing
202
+ existing.required_by << existing
203
+ activated['bundler'] = existing
203
204
  end
204
205
 
205
206
  if current.requirement.satisfied_by?(existing.version)
@@ -230,9 +231,10 @@ module Bundler
230
231
  parent ||= existing.required_by.last if existing.respond_to?(:required_by)
231
232
  # We track the spot where the current gem was activated because we need
232
233
  # to keep a list of every spot a failure happened.
233
- debug { " -> Jumping to: #{parent.name}" }
234
- if parent
235
- throw parent.name, existing.respond_to?(:required_by) && existing.required_by.last.name
234
+ if parent && parent.name != 'bundler'
235
+ debug { " -> Jumping to: #{parent.name}" }
236
+ required_by = existing.respond_to?(:required_by) && existing.required_by.last
237
+ throw parent.name, required_by && required_by.name
236
238
  else
237
239
  # The original set of dependencies conflict with the base set of specs
238
240
  # passed to the resolver. This is by definition an impossible resolve.
@@ -272,7 +274,7 @@ module Bundler
272
274
  else
273
275
  message = "Could not find gem '#{current}' "
274
276
  if @index.sources.include?(Bundler::Source::Rubygems)
275
- message << "in any of the gem sources."
277
+ message << "in any of the gem sources listed in your Gemfile."
276
278
  else
277
279
  message << "in the gems available on this machine."
278
280
  end
@@ -413,13 +415,23 @@ module Bundler
413
415
 
414
416
  o << gem_message(requirement)
415
417
 
418
+ # If the origin is "bundler", the conflict is us
419
+ if origin.name == "bundler"
420
+ o << " Current Bundler version:\n"
421
+ newer_bundler_required = requirement.requirement > Gem::Requirement.new(origin.version)
416
422
  # If the origin is a LockfileParser, it does not respond_to :required_by
417
- unless origin.respond_to?(:required_by) && required_by = origin.required_by.first
423
+ elsif !origin.respond_to?(:required_by) || !(required_by = origin.required_by.first)
418
424
  o << " In snapshot (Gemfile.lock):\n"
419
425
  end
420
426
 
421
427
  o << gem_message(origin)
422
428
 
429
+ # If the bundle wants a newer bundler than the running bundler, explain
430
+ if origin.name == "bundler" && newer_bundler_required
431
+ o << "Your version of Bundler is older than the one requested by the Gemfile.\n"
432
+ o << "Perhaps you need to update Bundler by running `gem install bundler`."
433
+ end
434
+
423
435
  # origin is nil if the required gem and version cannot be found in any of
424
436
  # the specified sources
425
437
  else
@@ -449,6 +461,7 @@ module Bundler
449
461
  end
450
462
 
451
463
  end
464
+ o
452
465
  end
453
466
  end
454
467
  end
@@ -121,7 +121,7 @@ module Gem
121
121
  class Platform
122
122
  JAVA = Gem::Platform.new('java')
123
123
  MSWIN = Gem::Platform.new('mswin32')
124
- MING = Gem::Platform.new('x86-mingw32')
124
+ MINGW = Gem::Platform.new('x86-mingw32')
125
125
 
126
126
  def hash
127
127
  @cpu.hash ^ @os.hash ^ @version.hash
@@ -172,16 +172,19 @@ module Bundler
172
172
  GENERICS = [
173
173
  Gem::Platform::JAVA,
174
174
  Gem::Platform::MSWIN,
175
- Gem::Platform::MING,
175
+ Gem::Platform::MINGW,
176
176
  Gem::Platform::RUBY
177
177
  ]
178
178
 
179
179
  def generic(p)
180
- if p == Gem::Platform::RUBY
181
- return p
182
- end
180
+ return p if p == Gem::Platform::RUBY
183
181
 
184
- GENERIC_CACHE[p] ||= GENERICS.find { |p2| p =~ p2 } || Gem::Platform::RUBY
182
+ GENERIC_CACHE[p] ||= begin
183
+ found = GENERICS.find do |p2|
184
+ p2.is_a?(Gem::Platform) && p.os == p2.os
185
+ end
186
+ found || Gem::Platform::RUBY
187
+ end
185
188
  end
186
189
  end
187
190
 
@@ -101,7 +101,7 @@ module Bundler
101
101
  spec = Gem::Format.from_file_by_path(path).spec
102
102
 
103
103
  resolve.any? do |s|
104
- s.name == spec.name && s.version == spec.version
104
+ s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git)
105
105
  end
106
106
  end
107
107
 
data/lib/bundler/setup.rb CHANGED
@@ -6,6 +6,7 @@ if Bundler::SharedHelpers.in_bundle?
6
6
  Bundler.setup
7
7
  rescue Bundler::BundlerError => e
8
8
  puts "\e[31m#{e.message}\e[0m"
9
+ puts e.backtrace.join("\n") if ENV["DEBUG"]
9
10
  exit e.status_code
10
11
  end
11
12
 
@@ -18,7 +18,7 @@ module Bundler
18
18
 
19
19
  def default_gemfile
20
20
  gemfile = find_gemfile
21
- gemfile or raise GemfileNotFound, "Could not locate Gemfile"
21
+ raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
22
22
  Pathname.new(gemfile)
23
23
  end
24
24
 
@@ -33,12 +33,19 @@ module Bundler
33
33
  private
34
34
 
35
35
  def find_gemfile
36
- return ENV['BUNDLE_GEMFILE'] if ENV['BUNDLE_GEMFILE']
36
+ given = ENV['BUNDLE_GEMFILE']
37
+ return given if given && !given.empty?
37
38
 
38
39
  previous = nil
39
40
  current = File.expand_path(Dir.pwd)
40
41
 
41
42
  until !File.directory?(current) || current == previous
43
+ if ENV['BUNDLE_SPEC_RUN']
44
+ # avoid stepping above the tmp directory when testing
45
+ return nil if File.file?(File.join(current, 'bundler.gemspec'))
46
+ end
47
+
48
+ # otherwise return the Gemfile if it's there
42
49
  filename = File.join(current, 'Gemfile')
43
50
  return filename if File.file?(filename)
44
51
  current, previous = File.expand_path("..", current), current
@@ -50,9 +57,9 @@ module Bundler
50
57
  if defined?(::Gem)
51
58
  me = File.expand_path("../../", __FILE__)
52
59
  $LOAD_PATH.reject! do |p|
53
- next if File.expand_path(p).include?(me)
60
+ next if File.expand_path(p) =~ /^#{me}/
54
61
  p != File.dirname(__FILE__) &&
55
- Gem.path.any? { |gp| p.include?(gp) }
62
+ Gem.path.any?{|gp| p =~ /^#{gp}/ }
56
63
  end
57
64
  $LOAD_PATH.uniq!
58
65
  end
@@ -39,12 +39,6 @@ module Bundler
39
39
 
40
40
  alias == eql?
41
41
 
42
- # Not really needed, but it seems good to implement this method for interface
43
- # consistency. Source name is mostly used to identify Path & Git sources
44
- def name
45
- ":gems"
46
- end
47
-
48
42
  def options
49
43
  { "remotes" => @remotes.map { |r| r.to_s } }
50
44
  end
@@ -62,9 +56,10 @@ module Bundler
62
56
  end
63
57
 
64
58
  def to_s
65
- remotes = self.remotes.map { |r| r.to_s }.join(', ')
66
- "rubygems repository #{remotes}"
59
+ remote_names = self.remotes.map { |r| r.to_s }.join(', ')
60
+ "rubygems repository #{remote_names}"
67
61
  end
62
+ alias_method :name, :to_s
68
63
 
69
64
  def specs
70
65
  @specs ||= fetch_specs
@@ -193,8 +188,18 @@ module Bundler
193
188
  idx = Index.new
194
189
  @caches.each do |path|
195
190
  Dir["#{path}/*.gem"].each do |gemfile|
196
- next if name == 'bundler'
197
- s = Gem::Format.from_file_by_path(gemfile).spec
191
+ next if gemfile =~ /bundler\-[\d\.]+?\.gem/
192
+
193
+ # Try to skip decompressing the gem to get at the gemspec if possible
194
+ cached_gemspec = gemfile.gsub(%r{cache/(.*?)\.gem}, 'specifications/\1.gemspec')
195
+ s = Gem::Specification.load(cached_gemspec) if File.exist?(cached_gemspec)
196
+
197
+ begin
198
+ s ||= Gem::Format.from_file_by_path(gemfile).spec
199
+ rescue Gem::Package::FormatError
200
+ raise GemspecError, "Could not read gem at #{gemfile}. It may be corrupted."
201
+ end
202
+
198
203
  s.source = self
199
204
  idx << s
200
205
  end
@@ -313,7 +318,7 @@ module Bundler
313
318
 
314
319
  def eql?(o)
315
320
  o.instance_of?(Path) &&
316
- path == o.path &&
321
+ path.expand_path(Bundler.root) == o.path.expand_path(Bundler.root) &&
317
322
  name == o.name &&
318
323
  version == o.version
319
324
  end
@@ -327,7 +332,7 @@ module Bundler
327
332
  def load_spec_files
328
333
  index = Index.new
329
334
 
330
- expanded_path = path.expand_path
335
+ expanded_path = path.expand_path(Bundler.root)
331
336
 
332
337
  if File.directory?(expanded_path)
333
338
  Dir["#{expanded_path}/#{@glob}"].each do |file|
@@ -403,7 +408,7 @@ module Bundler
403
408
  alias specs local_specs
404
409
 
405
410
  def cache(spec)
406
- unless path.to_s.index(Bundler.root.to_s) == 0
411
+ unless path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
407
412
  Bundler.ui.warn " * #{spec.name} at `#{path}` will not be cached."
408
413
  end
409
414
  end
@@ -460,6 +465,10 @@ module Bundler
460
465
 
461
466
  def initialize(options)
462
467
  super
468
+
469
+ # stringify options that could be set as symbols
470
+ %w(ref branch tag revision).each{|k| options[k] = options[k].to_s if options[k] }
471
+
463
472
  @uri = options["uri"]
464
473
  @ref = options["ref"] || options["branch"] || options["tag"] || 'master'
465
474
  @revision = options["revision"]
@@ -494,8 +503,8 @@ module Bundler
494
503
  alias == eql?
495
504
 
496
505
  def to_s
497
- ref = @options["ref"] ? shortref_for_display(@options["ref"]) : @ref
498
- "#{@uri} (at #{ref})"
506
+ sref = options["ref"] ? shortref_for_display(options["ref"]) : ref
507
+ "#{uri} (at #{sref})"
499
508
  end
500
509
 
501
510
  def name