bundler 1.4.0.rc.1 → 1.5.0.rc.1

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 (58) hide show
  1. data/.travis.yml +18 -15
  2. data/CHANGELOG.md +23 -2
  3. data/Rakefile +3 -1
  4. data/bundler.gemspec +1 -1
  5. data/lib/bundler.rb +3 -2
  6. data/lib/bundler/capistrano.rb +1 -0
  7. data/lib/bundler/cli.rb +19 -5
  8. data/lib/bundler/definition.rb +6 -2
  9. data/lib/bundler/dsl.rb +7 -3
  10. data/lib/bundler/endpoint_specification.rb +1 -1
  11. data/lib/bundler/fetcher.rb +22 -41
  12. data/lib/bundler/installer.rb +1 -11
  13. data/lib/bundler/lazy_specification.rb +1 -1
  14. data/lib/bundler/parallel_workers/unix_worker.rb +6 -0
  15. data/lib/bundler/remote_specification.rb +1 -1
  16. data/lib/bundler/retry.rb +4 -3
  17. data/lib/bundler/ruby_version.rb +1 -1
  18. data/lib/bundler/rubygems_ext.rb +7 -2
  19. data/lib/bundler/rubygems_integration.rb +31 -30
  20. data/lib/bundler/settings.rb +21 -0
  21. data/lib/bundler/source.rb +13 -2
  22. data/lib/bundler/source/git/git_proxy.rb +1 -1
  23. data/lib/bundler/source/rubygems.rb +43 -13
  24. data/lib/bundler/templates/newgem/README.md.tt +1 -1
  25. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +2 -2
  26. data/lib/bundler/version.rb +1 -1
  27. data/man/bundle-config.ronn +9 -0
  28. data/man/bundle-install.ronn +9 -5
  29. data/man/gemfile.5.ronn +6 -0
  30. data/spec/bundler/retry_spec.rb +26 -3
  31. data/spec/commands/config_spec.rb +14 -0
  32. data/spec/{integration/inject.rb → commands/inject_spec.rb} +0 -0
  33. data/spec/commands/newgem_spec.rb +2 -2
  34. data/spec/commands/outdated_spec.rb +17 -0
  35. data/spec/install/binstubs_spec.rb +24 -0
  36. data/spec/install/bundler_spec.rb +146 -0
  37. data/spec/install/{gemspec_spec.rb → gemfile/gemspec_spec.rb} +0 -0
  38. data/spec/install/{git_spec.rb → gemfile/git_spec.rb} +2 -2
  39. data/spec/install/gemfile/path_spec.rb +468 -0
  40. data/spec/install/gemfile_spec.rb +44 -0
  41. data/spec/install/gems/groups_spec.rb +236 -177
  42. data/spec/install/gems/mirror_spec.rb +39 -0
  43. data/spec/install/gems/platform_spec.rb +2 -14
  44. data/spec/install/gems/simple_case_spec.rb +1 -450
  45. data/spec/install/gemspecs_spec.rb +50 -0
  46. data/spec/install/path_spec.rb +91 -409
  47. data/spec/install/prereleases_spec.rb +43 -0
  48. data/spec/other/bundle_ruby_spec.rb +2 -2
  49. data/spec/other/ext_spec.rb +1 -1
  50. data/spec/other/platform_spec.rb +29 -2
  51. data/spec/realworld/parallel_install_spec.rb +2 -1
  52. data/spec/realworld/parallel_update_spec.rb +31 -0
  53. data/spec/runtime/platform_spec.rb +2 -2
  54. data/spec/spec_helper.rb +2 -2
  55. data/spec/support/{rubygems_hax/platform.rb → hax.rb} +0 -0
  56. metadata +110 -67
  57. checksums.yaml +0 -7
  58. data/spec/install/invalid_spec.rb +0 -50
@@ -14,6 +14,12 @@ module Bundler
14
14
  end
15
15
  end
16
16
 
17
+ def initialize(size, job)
18
+ # Close the persistent connections for the main thread before forking
19
+ Net::HTTP::Persistent.new('bundler', :ENV).shutdown
20
+ super
21
+ end
22
+
17
23
  private
18
24
 
19
25
  # Start forked workers for downloading gems. This version of worker
@@ -10,7 +10,7 @@ module Bundler
10
10
  include MatchPlatform
11
11
 
12
12
  attr_reader :name, :version, :platform
13
- attr_accessor :source
13
+ attr_accessor :source, :source_uri
14
14
 
15
15
  def initialize(name, version, platform, spec_fetcher)
16
16
  @name = name
@@ -8,9 +8,10 @@ module Bundler
8
8
  attr_accessor :attempts
9
9
  end
10
10
 
11
- def initialize(name, attempts = nil)
11
+ def initialize(name, exceptions = nil, attempts = nil)
12
12
  @name = name
13
13
  attempts ||= default_attempts
14
+ @exceptions = Array(exceptions) || []
14
15
  @total_runs = attempts.next # will run once, then upto attempts.times
15
16
  end
16
17
 
@@ -41,9 +42,9 @@ module Bundler
41
42
 
42
43
  def fail(e)
43
44
  @failed = true
44
- raise e if last_attempt?
45
+ raise e if last_attempt? || @exceptions.any?{|k| k === e }
45
46
  return true unless name
46
- Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.message}"
47
+ Bundler.ui.warn "Retrying#{" #{name}" if name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}"
47
48
  end
48
49
 
49
50
  def keep_trying?
@@ -111,7 +111,7 @@ module Bundler
111
111
  end
112
112
 
113
113
  def patchlevel
114
- RUBY_PATCHLEVEL
114
+ RUBY_PATCHLEVEL.to_s
115
115
  end
116
116
  end
117
117
  end
@@ -13,7 +13,10 @@ module Gem
13
13
  @loaded_stacks = Hash.new { |h,k| h[k] = [] }
14
14
 
15
15
  class Specification
16
- attr_accessor :source, :location, :relative_loaded_from
16
+ attr_accessor :source_uri, :location, :relative_loaded_from
17
+
18
+ remove_method :source if instance_methods(false).include?(:source)
19
+ attr_accessor :source
17
20
 
18
21
  alias_method :rg_full_gem_path, :full_gem_path
19
22
  alias_method :rg_loaded_from, :loaded_from
@@ -31,6 +34,8 @@ module Gem
31
34
  end
32
35
 
33
36
  def load_paths
37
+ return full_require_paths if respond_to?(:full_require_paths)
38
+
34
39
  require_paths.map do |require_path|
35
40
  if require_path.include?(full_gem_path)
36
41
  require_path
@@ -41,7 +46,7 @@ module Gem
41
46
  end
42
47
 
43
48
  # RubyGems 1.8+ used only.
44
- remove_method :gem_dir if method_defined? :gem_dir
49
+ remove_method :gem_dir if instance_methods(false).include?(:gem_dir)
45
50
  def gem_dir
46
51
  full_gem_path
47
52
  end
@@ -187,6 +187,7 @@ module Bundler
187
187
  end
188
188
 
189
189
  def download_gem(spec, uri, path)
190
+ uri = Bundler::Source.mirror_for(uri)
190
191
  Gem::RemoteFetcher.fetcher.download(spec, uri, path)
191
192
  end
192
193
 
@@ -212,6 +213,8 @@ module Bundler
212
213
  end
213
214
 
214
215
  def replace_gem(specs)
216
+ reverse_rubygems_kernel_mixin
217
+
215
218
  executables = specs.map { |s| s.executables }.flatten
216
219
 
217
220
  ::Kernel.send(:define_method, :gem) do |dep, *reqs|
@@ -252,21 +255,9 @@ module Bundler
252
255
  end
253
256
  end
254
257
 
255
- def stub_source_index137(specs)
256
- # Rubygems versions lower than 1.7 use SourceIndex#from_gems_in
257
- source_index_class = (class << Gem::SourceIndex ; self ; end)
258
- source_index_class.send(:remove_method, :from_gems_in)
259
- source_index_class.send(:define_method, :from_gems_in) do |*args|
260
- source_index = Gem::SourceIndex.new
261
- source_index.spec_dirs = *args
262
- source_index.add_specs(*specs)
263
- source_index
264
- end
265
- end
266
-
267
- def stub_source_index170(specs)
258
+ def stub_source_index(specs)
268
259
  Gem::SourceIndex.send(:alias_method, :old_initialize, :initialize)
269
- Gem::SourceIndex.send(:define_method, :initialize) do |*args|
260
+ redefine_method(Gem::SourceIndex, :initialize) do |*args|
270
261
  @gems = {}
271
262
  # You're looking at this thinking: Oh! This is how I make those
272
263
  # rubygems deprecations go away!
@@ -289,8 +280,7 @@ module Bundler
289
280
  # +specs+
290
281
  def replace_bin_path(specs)
291
282
  gem_class = (class << Gem ; self ; end)
292
- gem_class.send(:remove_method, :bin_path)
293
- gem_class.send(:define_method, :bin_path) do |name, *args|
283
+ redefine_method(gem_class, :bin_path) do |name, *args|
294
284
  exec_name = args.first
295
285
 
296
286
  if exec_name == 'bundle'
@@ -317,15 +307,12 @@ module Bundler
317
307
  # we don't #refresh, so stub it out.
318
308
  def replace_refresh
319
309
  gem_class = (class << Gem ; self ; end)
320
- gem_class.send(:remove_method, :refresh)
321
- gem_class.send(:define_method, :refresh) { }
310
+ redefine_method(gem_class, :refresh) { }
322
311
  end
323
312
 
324
313
  # Replace or hook into Rubygems to provide a bundlerized view
325
314
  # of the world.
326
315
  def replace_entrypoints(specs)
327
- reverse_rubygems_kernel_mixin
328
-
329
316
  replace_gem(specs)
330
317
 
331
318
  stub_rubygems(specs)
@@ -339,7 +326,7 @@ module Bundler
339
326
  # This backports the correct segment generation code from Rubygems 1.4+
340
327
  # by monkeypatching it into the method in Rubygems 1.3.6 and 1.3.7.
341
328
  def backport_segment_generation
342
- Gem::Version.send(:define_method, :segments) do
329
+ redefine_method(Gem::Version, :segments) do
343
330
  @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
344
331
  /^\d+$/ =~ s ? s.to_i : s
345
332
  end
@@ -348,7 +335,7 @@ module Bundler
348
335
 
349
336
  # This backport fixes the marshaling of @segments.
350
337
  def backport_yaml_initialize
351
- Gem::Version.send(:define_method, :yaml_initialize) do |tag, map|
338
+ redefine_method(Gem::Version, :yaml_initialize) do |tag, map|
352
339
  @version = map['version']
353
340
  @segments = nil
354
341
  @hash = nil
@@ -358,32 +345,39 @@ module Bundler
358
345
  # This backports base_dir which replaces installation path
359
346
  # Rubygems 1.8+
360
347
  def backport_base_dir
361
- Gem::Specification.send(:define_method, :base_dir) do
348
+ redefine_method(Gem::Specification, :base_dir) do
362
349
  return Gem.dir unless loaded_from
363
350
  File.dirname File.dirname loaded_from
364
351
  end
365
352
  end
366
353
 
367
354
  def backport_cache_file
368
- Gem::Specification.send(:define_method, :cache_dir) do
355
+ redefine_method(Gem::Specification, :cache_dir) do
369
356
  @cache_dir ||= File.join base_dir, "cache"
370
357
  end
371
358
 
372
- Gem::Specification.send(:define_method, :cache_file) do
359
+ redefine_method(Gem::Specification, :cache_file) do
373
360
  @cache_file ||= File.join cache_dir, "#{full_name}.gem"
374
361
  end
375
362
  end
376
363
 
377
364
  def backport_spec_file
378
- Gem::Specification.send(:define_method, :spec_dir) do
365
+ redefine_method(Gem::Specification, :spec_dir) do
379
366
  @spec_dir ||= File.join base_dir, "specifications"
380
367
  end
381
368
 
382
- Gem::Specification.send(:define_method, :spec_file) do
369
+ redefine_method(Gem::Specification, :spec_file) do
383
370
  @spec_file ||= File.join spec_dir, "#{full_name}.gemspec"
384
371
  end
385
372
  end
386
373
 
374
+ def redefine_method(klass, method, &block)
375
+ if klass.instance_methods(false).include?(method)
376
+ klass.send(:remove_method, method)
377
+ end
378
+ klass.send(:define_method, method, &block)
379
+ end
380
+
387
381
  # Rubygems 1.4 through 1.6
388
382
  class Legacy < RubygemsIntegration
389
383
  def initialize
@@ -395,7 +389,14 @@ module Bundler
395
389
  end
396
390
 
397
391
  def stub_rubygems(specs)
398
- stub_source_index137(specs)
392
+ # Rubygems versions lower than 1.7 use SourceIndex#from_gems_in
393
+ source_index_class = (class << Gem::SourceIndex ; self ; end)
394
+ source_index_class.send(:define_method, :from_gems_in) do |*args|
395
+ source_index = Gem::SourceIndex.new
396
+ source_index.spec_dirs = *args
397
+ source_index.add_specs(*specs)
398
+ source_index
399
+ end
399
400
  end
400
401
 
401
402
  def all_specs
@@ -418,7 +419,7 @@ module Bundler
418
419
  # Rubygems 1.7
419
420
  class Transitional < Legacy
420
421
  def stub_rubygems(specs)
421
- stub_source_index170(specs)
422
+ stub_source_index(specs)
422
423
  end
423
424
  end
424
425
 
@@ -431,7 +432,7 @@ module Bundler
431
432
  Gem::Specification.all = specs
432
433
  }
433
434
 
434
- stub_source_index170(specs)
435
+ stub_source_index(specs)
435
436
  end
436
437
 
437
438
  def all_specs
@@ -29,6 +29,7 @@ module Bundler
29
29
 
30
30
  def all
31
31
  env_keys = ENV.keys.select { |k| k =~ /BUNDLE_.*/ }
32
+
32
33
  keys = @global_config.keys | @local_config.keys | env_keys
33
34
 
34
35
  keys.map do |key|
@@ -46,6 +47,16 @@ module Bundler
46
47
  repos
47
48
  end
48
49
 
50
+ def gem_mirrors
51
+ all.inject({}) do |h, k|
52
+ if k =~ /^mirror\./
53
+ uri = normalize_uri($')
54
+ h[uri] = normalize_uri(self[k])
55
+ end
56
+ h
57
+ end
58
+ end
59
+
49
60
  def locations(key)
50
61
  key = key_for(key)
51
62
  locations = {}
@@ -149,5 +160,15 @@ module Bundler
149
160
  end
150
161
  end
151
162
 
163
+ # TODO: duplicates Rubygems#normalize_uri
164
+ # TODO: is this the correct place to validate mirror URIs?
165
+ def normalize_uri(uri)
166
+ uri = uri.to_s
167
+ uri = "#{uri}/" unless uri =~ %r[/\Z]
168
+ uri = URI(uri)
169
+ raise ArgumentError, "Gem mirror sources must be absolute URIs (configured: #{mirror_source})" unless uri.absolute?
170
+ uri
171
+ end
172
+
152
173
  end
153
174
  end
@@ -1,7 +1,18 @@
1
1
  module Bundler
2
2
  module Source
3
3
  autoload :Rubygems, 'bundler/source/rubygems'
4
- autoload :Path, 'bundler/source/path'
5
- autoload :Git, 'bundler/source/git'
4
+ autoload :Path, 'bundler/source/path'
5
+ autoload :Git, 'bundler/source/git'
6
+
7
+ def self.mirror_for(uri)
8
+ uri = URI(uri.to_s) unless uri.is_a?(URI)
9
+
10
+ # Settings keys are all downcased
11
+ mirrors = Bundler.settings.gem_mirrors
12
+ normalized_key = URI(uri.to_s.downcase)
13
+
14
+ mirrors[normalized_key] || uri
15
+ end
16
+
6
17
  end
7
18
  end
@@ -13,7 +13,7 @@ module Bundler
13
13
  def initialize(command)
14
14
  msg = "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, "
15
15
  msg << "this error message could probably be more useful. Please submit a ticket at http://github.com/bundler/bundler/issues "
16
- mag << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
16
+ msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
17
17
  super msg
18
18
  end
19
19
  end
@@ -72,6 +72,14 @@ module Bundler
72
72
  return ["Using #{spec.name} (#{spec.version})", nil]
73
73
  end
74
74
 
75
+ # Download the gem to get the spec, because some specs that are returned
76
+ # by rubygems.org are broken and wrong.
77
+ if spec.source_uri
78
+ path = Fetcher.download_gem_from_uri(spec, spec.source_uri)
79
+ s = Bundler.rubygems.spec_from_gem(path, Bundler.settings["trust-policy"])
80
+ spec.__swap__(s)
81
+ end
82
+
75
83
  install_message = "Installing #{spec.name} (#{spec.version})"
76
84
  path = cached_gem(spec)
77
85
  if Bundler.requires_sudo?
@@ -221,24 +229,46 @@ module Bundler
221
229
  index_fetchers = fetchers - api_fetchers
222
230
 
223
231
  # gather lists from non-api sites
224
- index_fetchers.each { |f| idx.use f.specs(nil, self) }
232
+ index_fetchers.each do |f|
233
+ Bundler.ui.info "Fetching source index from #{f.uri}"
234
+ idx.use f.specs(nil, self)
235
+ end
225
236
  return idx if api_fetchers.empty?
226
237
 
227
238
  # because ensuring we have all the gems we need involves downloading
228
239
  # the gemspecs of those gems, if the non-api sites contain more than
229
240
  # about 100 gems, we just treat all sites as non-api for speed.
230
- if idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT
231
- api_fetchers.each { |f| idx.use f.specs(dependency_names, self) }
232
-
233
- # it's possible that gems from one source depend on gems from some
234
- # other source, so now we download gemspecs and iterate over those
235
- # dependencies, looking for gems we don't have info on yet.
236
- unmet = idx.unmet_dependency_names
237
-
238
- # if there are any cross-site gems we missed, get them now
239
- api_fetchers.each { |f| idx.use f.specs(unmet, self) } if unmet.any?
240
- else
241
- api_fetchers.each { |f| idx.use f.specs(nil, self) }
241
+ allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT
242
+
243
+ if allow_api
244
+ api_fetchers.each do |f|
245
+ Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug?
246
+ idx.use f.specs(dependency_names, self)
247
+ Bundler.ui.info "" if !Bundler.ui.debug? # new line now that the dots are over
248
+ end
249
+
250
+ if api_fetchers.all?{|f| f.use_api }
251
+ # it's possible that gems from one source depend on gems from some
252
+ # other source, so now we download gemspecs and iterate over those
253
+ # dependencies, looking for gems we don't have info on yet.
254
+ unmet = idx.unmet_dependency_names
255
+
256
+ # if there are any cross-site gems we missed, get them now
257
+ api_fetchers.each do |f|
258
+ Bundler.ui.info "Fetching additional metadata from #{f.uri}", Bundler.ui.debug?
259
+ idx.use f.specs(unmet, self)
260
+ Bundler.ui.info "" if !Bundler.ui.debug? # new line now that the dots are over
261
+ end if unmet.any?
262
+ else
263
+ allow_api = false
264
+ end
265
+ end
266
+
267
+ if !allow_api
268
+ api_fetchers.each do |f|
269
+ Bundler.ui.info "Fetching source index from #{f.uri}"
270
+ idx.use f.specs(nil, self)
271
+ end
242
272
  end
243
273
 
244
274
  return idx
@@ -22,7 +22,7 @@ TODO: Write usage instructions here
22
22
 
23
23
  ## Contributing
24
24
 
25
- 1. Fork it
25
+ 1. Fork it ( http://github.com/<my-github-username>/<%=config[:name]%>/fork )
26
26
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
27
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
28
  4. Push to the branch (`git push origin my-new-feature`)
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe <%= config[:constant_name] %> do
4
4
  it 'should have a version number' do
5
- <%= config[:constant_name] %>::VERSION.should_not be_nil
5
+ expect(<%= config[:constant_name] %>::VERSION).not_to be nil
6
6
  end
7
7
 
8
8
  it 'should do something useful' do
9
- false.should be_true
9
+ expect(false).to be true
10
10
  end
11
11
  end
@@ -2,5 +2,5 @@ module Bundler
2
2
  # We're doing this because we might write tests that deal
3
3
  # with other versions of bundler and we are unsure how to
4
4
  # handle this better.
5
- VERSION = "1.4.0.rc.1" unless defined?(::Bundler::VERSION)
5
+ VERSION = "1.5.0.rc.1" unless defined?(::Bundler::VERSION)
6
6
  end
@@ -138,3 +138,12 @@ accidental locking to a different branch.
138
138
  Finally, Bundler also ensures that the current revision in the
139
139
  `Gemfile.lock` exists in the local git repository. By doing this, Bundler
140
140
  forces you to fetch the latest changes in the remotes.
141
+
142
+ ## MIRRORS OF GEM REPOSITORIES
143
+
144
+ Bundler supports overriding gem sources with mirrors. This allows you to
145
+ configure rubygems.org as the gem source in your Gemfile while still using your
146
+ mirror to fetch gems.
147
+
148
+ bundle config mirror.http://rubygems.org http://rubygems-mirror.org
149
+
@@ -11,6 +11,7 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
11
11
  [--standalone[=GROUP1[ GROUP2...]]]
12
12
  [--trust-policy=POLICY]
13
13
  [--jobs=SIZE]
14
+ [--retry=TRIES]
14
15
  [--no-cache]
15
16
  [--quiet]
16
17
 
@@ -41,11 +42,11 @@ update process below under [CONSERVATIVE UPDATING][].
41
42
  to it.
42
43
 
43
44
  * `--path=<path>`:
44
- The location to install the gems in the bundle to. This defaults
45
- to the gem home, which is the location that `gem install` installs
46
- gems to. This means that, by default, gems installed without a
47
- `--path` setting will show up in `gem list`. This setting is a
48
- [remembered option][REMEMBERED OPTIONS].
45
+ The location to install the gems in the bundle to. This defaults to
46
+ Rubygems' gem home, which is also the default location where `gem
47
+ install` installs gems. This means that, by default, gems installed
48
+ without a `--path` setting will show up in `gem list`. This setting is
49
+ a [remembered option][REMEMBERED OPTIONS].
49
50
 
50
51
  * `--system`:
51
52
  Installs the gems in the bundle to the system location. This
@@ -92,6 +93,9 @@ update process below under [CONSERVATIVE UPDATING][].
92
93
  * `--jobs=[<size>]`:
93
94
  Install gems parallely by starting <size> number of parallel workers.
94
95
 
96
+ * `--retry[<tries]`:
97
+ Retries failed network or git requests <tries> times.
98
+
95
99
  * `--no-cache`:
96
100
  Do not update the cache in `vendor/cache` with the newly bundled gems. This
97
101
  does not remove any existing cached gems, only stops the newly bundled gems