bundler 1.1.pre.4 → 1.1.pre.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 (65) hide show
  1. data/.travis.yml +1 -0
  2. data/CHANGELOG.md +51 -2
  3. data/ISSUES.md +25 -11
  4. data/README.md +3 -3
  5. data/Rakefile +44 -48
  6. data/lib/bundler.rb +21 -20
  7. data/lib/bundler/cli.rb +46 -11
  8. data/lib/bundler/definition.rb +6 -4
  9. data/lib/bundler/dependency.rb +5 -0
  10. data/lib/bundler/dsl.rb +1 -7
  11. data/lib/bundler/endpoint_specification.rb +22 -0
  12. data/lib/bundler/fetcher.rb +76 -22
  13. data/lib/bundler/gem_helper.rb +2 -7
  14. data/lib/bundler/gem_tasks.rb +2 -0
  15. data/lib/bundler/index.rb +48 -41
  16. data/lib/bundler/installer.rb +5 -0
  17. data/lib/bundler/lazy_specification.rb +7 -6
  18. data/lib/bundler/resolver.rb +1 -1
  19. data/lib/bundler/rubygems_ext.rb +1 -1
  20. data/lib/bundler/rubygems_integration.rb +69 -31
  21. data/lib/bundler/runtime.rb +2 -2
  22. data/lib/bundler/setup.rb +3 -0
  23. data/lib/bundler/shared_helpers.rb +2 -2
  24. data/lib/bundler/source.rb +48 -46
  25. data/lib/bundler/spec_set.rb +1 -0
  26. data/lib/bundler/templates/newgem/Gemfile.tt +1 -1
  27. data/lib/bundler/templates/newgem/Rakefile.tt +2 -2
  28. data/lib/bundler/templates/newgem/bin/newgem.tt +1 -1
  29. data/lib/bundler/templates/newgem/gitignore.tt +14 -1
  30. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +2 -0
  31. data/lib/bundler/templates/newgem/newgem.gemspec.tt +13 -17
  32. data/lib/bundler/ui.rb +29 -15
  33. data/lib/bundler/vendor/net/http/persistent.rb +4 -0
  34. data/lib/bundler/vendored_thor.rb +7 -0
  35. data/lib/bundler/version.rb +1 -1
  36. data/man/bundle-install.ronn +7 -0
  37. data/man/bundle.ronn +6 -0
  38. data/man/gemfile.5.ronn +2 -0
  39. data/spec/cache/gems_spec.rb +11 -0
  40. data/spec/install/deploy_spec.rb +1 -1
  41. data/spec/install/gems/dependency_api_spec.rb +62 -7
  42. data/spec/install/gems/groups_spec.rb +3 -3
  43. data/spec/install/gems/post_install_spec.rb +47 -0
  44. data/spec/install/gems/sudo_spec.rb +3 -2
  45. data/spec/install/git_spec.rb +1 -2
  46. data/spec/install/path_spec.rb +1 -1
  47. data/spec/lock/lockfile_spec.rb +1 -1
  48. data/spec/other/check_spec.rb +30 -6
  49. data/spec/other/exec_spec.rb +4 -33
  50. data/spec/other/init_spec.rb +3 -3
  51. data/spec/other/newgem_spec.rb +5 -1
  52. data/spec/other/outdated_spec.rb +36 -6
  53. data/spec/quality_spec.rb +5 -1
  54. data/spec/runtime/require_spec.rb +10 -10
  55. data/spec/runtime/setup_spec.rb +31 -8
  56. data/spec/spec_helper.rb +1 -5
  57. data/spec/support/artifice/endpoint.rb +4 -0
  58. data/spec/support/artifice/endpoint_basic_authentication.rb +13 -0
  59. data/spec/support/artifice/endpoint_fallback.rb +0 -4
  60. data/spec/support/artifice/endpoint_redirect.rb +4 -0
  61. data/spec/support/builders.rb +6 -1
  62. data/spec/support/matchers.rb +1 -1
  63. data/spec/support/rubygems_ext.rb +4 -3
  64. data/spec/update/git_spec.rb +2 -2
  65. metadata +55 -143
@@ -160,16 +160,18 @@ module Bundler
160
160
  def index
161
161
  @index ||= Index.build do |idx|
162
162
  @sources.each do |s|
163
- idx.use s.specs(@dependencies)
163
+ s.dependencies = @dependencies if s.is_a?(Bundler::Source::Rubygems)
164
+ idx.add_source s.specs
164
165
  end
165
166
  end
166
167
  end
167
168
 
169
+ # used when frozen is enabled so we can find the bundler
170
+ # spec, even if (say) a git gem is not checked out.
168
171
  def rubygems_index
169
172
  @rubygems_index ||= Index.build do |idx|
170
- @sources.find_all{|s| s.is_a?(Source::Rubygems) }.each do |s|
171
- idx.use s.specs
172
- end
173
+ rubygems = @sources.find{|s| s.is_a?(Source::Rubygems) }
174
+ idx.add_source rubygems.specs
173
175
  end
174
176
  end
175
177
 
@@ -15,6 +15,7 @@ module Bundler
15
15
  :mri => Gem::Platform::RUBY,
16
16
  :mri_18 => Gem::Platform::RUBY,
17
17
  :mri_19 => Gem::Platform::RUBY,
18
+ :rbx => Gem::Platform::RUBY,
18
19
  :jruby => Gem::Platform::JAVA,
19
20
  :mswin => Gem::Platform::MSWIN,
20
21
  :mingw => Gem::Platform::MINGW,
@@ -107,6 +108,10 @@ module Bundler
107
108
  mri? && RUBY_VERSION >= "1.9"
108
109
  end
109
110
 
111
+ def rbx?
112
+ ruby? && defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
113
+ end
114
+
110
115
  def jruby?
111
116
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
112
117
  end
@@ -112,8 +112,7 @@ module Bundler
112
112
  end
113
113
 
114
114
  def to_definition(lockfile, unlock)
115
- @sources << @rubygems_source
116
- @sources.uniq!
115
+ @sources << @rubygems_source unless @sources.include?(@rubygems_source)
117
116
  Definition.new(lockfile, @dependencies, @sources, unlock)
118
117
  end
119
118
 
@@ -164,11 +163,6 @@ module Bundler
164
163
 
165
164
  private
166
165
 
167
- def rubygems_source(source)
168
- @rubygems_source.add_remote source
169
- @sources << @rubygems_source
170
- end
171
-
172
166
  def _normalize_hash(opts)
173
167
  # Cannot modify a hash during an iteration in 1.9
174
168
  opts.keys.each do |k|
@@ -0,0 +1,22 @@
1
+ require 'uri'
2
+
3
+ module Bundler
4
+ # used for Creating Specifications from the Gemcutter Endpoint
5
+ class EndpointSpecification < Gem::Specification
6
+ include MatchPlatform
7
+
8
+ attr_reader :name, :version, :platform, :dependencies
9
+ attr_accessor :source
10
+
11
+ def initialize(name, version, platform, dependencies)
12
+ @name = name
13
+ @version = version
14
+ @platform = platform
15
+ @dependencies = dependencies
16
+ end
17
+
18
+ def fetch_platform
19
+ @plaftorm
20
+ end
21
+ end
22
+ end
@@ -2,12 +2,17 @@ require 'uri'
2
2
  require 'net/http/persistent'
3
3
 
4
4
  module Bundler
5
+ # Handles all the fetching with the rubygems server
5
6
  class Fetcher
6
7
  REDIRECT_LIMIT = 5
7
8
 
9
+ class << self
10
+ attr_accessor :disable_endpoint
11
+ end
12
+
8
13
  def initialize(remote_uri)
9
14
  @remote_uri = remote_uri
10
- @@connection ||= Net::HTTP::Persistent.new
15
+ @@connection ||= Net::HTTP::Persistent.new nil, :ENV
11
16
  end
12
17
 
13
18
  # fetch a gem specification
@@ -21,25 +26,56 @@ module Bundler
21
26
  Marshal.load Gem.inflate(spec_rz)
22
27
  end
23
28
 
29
+ # return the specs in the bundler format as an index
30
+ def specs(gem_names, source, spec_fetch_map)
31
+ index = Index.new
32
+
33
+ fetch_remote_specs(gem_names)[@remote_uri].each do |name, version, platform, dependencies|
34
+ next if name == 'bundler'
35
+ spec = nil
36
+ if dependencies
37
+ spec = EndpointSpecification.new(name, version, platform, dependencies)
38
+ else
39
+ spec = RemoteSpecification.new(name, version, platform, self)
40
+ end
41
+ spec.source = source
42
+ spec_fetch_map[spec.full_name] = [spec, @remote_uri]
43
+ index << spec
44
+ end
45
+
46
+ index
47
+ end
48
+
24
49
  # fetch index
25
- def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [], &blk)
26
- return fetch_all_remote_specs(&blk) unless gem_names && @remote_uri.scheme != "file"
50
+ def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [])
51
+ return fetch_all_remote_specs if !gem_names || @remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
27
52
 
28
53
  query_list = gem_names - full_dependency_list
54
+ # only display the message on the first run
55
+ if full_dependency_list.empty?
56
+ Bundler.ui.info "Fetching dependency information from the API at #{@remote_uri}", false
57
+ else
58
+ Bundler.ui.info ".", false
59
+ end
60
+
29
61
  Bundler.ui.debug "Query List: #{query_list.inspect}"
30
- return {@remote_uri => last_spec_list}.each(&blk) if query_list.empty?
62
+ if query_list.empty?
63
+ Bundler.ui.info "\n"
64
+ return {@remote_uri => last_spec_list}
65
+ end
31
66
 
32
- spec_list, deps_list = fetch_dependency_remote_specs(query_list, &blk)
67
+ spec_list, deps_list = fetch_dependency_remote_specs(query_list)
33
68
  returned_gems = spec_list.map {|spec| spec.first }.uniq
34
69
 
35
- fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list, &blk)
70
+ fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
36
71
  # fall back to the legacy index in the following cases
37
72
  # 1.) Gemcutter Endpoint doesn't return a 200
38
73
  # 2.) Marshal blob doesn't load properly
39
74
  rescue HTTPError, TypeError => e
75
+ Bundler.ui.info "\nError using the API"
40
76
  Bundler.ui.debug "Error #{e.class} from Gemcutter Dependency Endpoint API: #{e.message}"
41
77
  Bundler.ui.debug e.backtrace
42
- fetch_all_remote_specs(&blk)
78
+ fetch_all_remote_specs
43
79
  end
44
80
 
45
81
  private
@@ -47,13 +83,20 @@ module Bundler
47
83
  def fetch(uri, counter = 0)
48
84
  raise HTTPError, "Too many redirects" if counter >= REDIRECT_LIMIT
49
85
 
50
- Bundler.ui.debug "Fetching from: #{uri}"
51
- response = @@connection.request(uri)
86
+ begin
87
+ Bundler.ui.debug "Fetching from: #{uri}"
88
+ response = @@connection.request(uri)
89
+ rescue SocketError, Timeout
90
+ raise Bundler::HTTPError, "Network error while fetching #{uri}"
91
+ end
92
+
52
93
  case response
53
94
  when Net::HTTPRedirection
54
95
  Bundler.ui.debug("HTTP Redirection")
55
- uri = URI.parse(response["location"])
56
- fetch(uri, counter + 1)
96
+ new_uri = URI.parse(response["location"])
97
+ new_uri.user = uri.user
98
+ new_uri.password = uri.password
99
+ fetch(new_uri, counter + 1)
57
100
  when Net::HTTPSuccess
58
101
  Bundler.ui.debug("HTTP Success")
59
102
  response.body
@@ -64,38 +107,49 @@ module Bundler
64
107
  end
65
108
 
66
109
  # fetch from Gemcutter Dependency Endpoint API
67
- def fetch_dependency_remote_specs(gem_names, &blk)
110
+ def fetch_dependency_remote_specs(gem_names)
68
111
  Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(' ')}"
69
112
  uri = URI.parse("#{@remote_uri}api/v1/dependencies?gems=#{gem_names.join(",")}")
70
113
  marshalled_deps = fetch(uri)
71
114
  gem_list = Marshal.load(marshalled_deps)
115
+ deps_list = []
72
116
 
73
117
  spec_list = gem_list.map do |s|
74
- [s[:name], Gem::Version.new(s[:number]), s[:platform]]
118
+ dependencies = s[:dependencies].map do |d|
119
+ name, requirement = d
120
+ dep = Gem::Dependency.new(name, requirement.split(", "))
121
+
122
+ deps_list << dep.name
123
+
124
+ dep
125
+ end
126
+
127
+ [s[:name], Gem::Version.new(s[:number]), s[:platform], dependencies]
75
128
  end
76
- deps_list = gem_list.map do |s|
77
- s[:dependencies].collect {|d| d.first }
78
- end.flatten.uniq
79
129
 
80
- [spec_list, deps_list]
130
+ [spec_list, deps_list.uniq]
81
131
  end
82
132
 
83
133
  # fetch from modern index: specs.4.8.gz
84
- def fetch_all_remote_specs(&blk)
134
+ def fetch_all_remote_specs
135
+ Bundler.ui.info "Fetching source index for #{@remote_uri}"
85
136
  Bundler.ui.debug "Fetching modern index"
86
137
  Gem.sources = ["#{@remote_uri}"]
138
+ spec_list = Hash.new { |h,k| h[k] = [] }
87
139
  begin
88
140
  # Fetch all specs, minus prerelease specs
89
- Gem::SpecFetcher.new.list(true, false).each(&blk)
141
+ spec_list = Gem::SpecFetcher.new.list(true, false)
90
142
  # Then fetch the prerelease specs
91
143
  begin
92
- Gem::SpecFetcher.new.list(false, true).each(&blk)
144
+ Gem::SpecFetcher.new.list(false, true).each {|k, v| spec_list[k] += v }
93
145
  rescue Gem::RemoteFetcher::FetchError
94
- Bundler.ui.warn "Could not fetch prerelease specs from #{self}"
146
+ Bundler.ui.warn "Could not fetch prerelease specs from #{@remote_uri}"
95
147
  end
96
148
  rescue Gem::RemoteFetcher::FetchError
97
- Bundler.ui.warn "Could not reach #{self}"
149
+ raise Bundler::HTTPError, "Could not reach #{@remote_uri}"
98
150
  end
151
+
152
+ return spec_list
99
153
  end
100
154
  end
101
155
  end
@@ -2,15 +2,10 @@ $:.unshift File.expand_path('../vendor', __FILE__)
2
2
  require 'thor'
3
3
  require 'bundler'
4
4
 
5
- begin
6
- # Support Rake > 0.8.7
7
- require 'rake/dsl_definition'
8
- include Rake::DSL
9
- rescue LoadError
10
- end
11
-
12
5
  module Bundler
13
6
  class GemHelper
7
+ include Rake::DSL if defined? Rake::DSL
8
+
14
9
  def self.install_tasks(opts = {})
15
10
  dir = opts[:dir] || Dir.pwd
16
11
  self.new(dir, opts[:name]).install
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_helper'
2
+ Bundler::GemHelper.install_tasks
@@ -33,40 +33,26 @@ module Bundler
33
33
  true
34
34
  end
35
35
 
36
- def search(query)
36
+ # Search this index's specs, and any source indexes that this index knows
37
+ # about, returning all of the results.
38
+ def search(query, base = nil)
39
+ results = local_search(query, base)
40
+ @sources.each do |source|
41
+ results += source.search(query, base)
42
+ end
43
+ results
44
+ end
45
+
46
+ def local_search(query, base = nil)
37
47
  case query
38
- when Gem::Specification, RemoteSpecification, LazySpecification then search_by_spec(query)
48
+ when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
39
49
  when String then specs_by_name(query)
40
- when Gem::Dependency then search_by_dependency(query)
50
+ when Gem::Dependency then search_by_dependency(query, base)
41
51
  else
42
52
  raise "You can't search for a #{query.inspect}."
43
53
  end
44
54
  end
45
55
 
46
- def specs_by_name(name)
47
- @specs[name]
48
- end
49
-
50
- def search_for_all_platforms(dependency, base = [])
51
- specs = specs_by_name(dependency.name) + base
52
-
53
- wants_prerelease = dependency.requirement.prerelease?
54
- only_prerelease = specs.all? {|spec| spec.version.prerelease? }
55
- found = specs.select { |spec| dependency.matches_spec?(spec) }
56
-
57
- unless wants_prerelease || only_prerelease
58
- found.reject! { |spec| spec.version.prerelease? }
59
- end
60
-
61
- found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
62
- end
63
-
64
- def sources
65
- specs.values.map do |specs|
66
- specs.map{|s| s.source }
67
- end.flatten.uniq
68
- end
69
-
70
56
  def source_types
71
57
  sources.map{|s| s.class }.uniq
72
58
  end
@@ -105,8 +91,43 @@ module Bundler
105
91
  end
106
92
  end
107
93
 
94
+ def add_source(index)
95
+ if index.is_a?(Index)
96
+ @sources << index
97
+ @sources.uniq! # need to use uniq! here instead of checking for the item before adding
98
+ else
99
+ raise ArgumentError, "Source must be an index, not #{index.class}"
100
+ end
101
+ end
102
+
108
103
  private
109
104
 
105
+ def specs_by_name(name)
106
+ @specs[name]
107
+ end
108
+
109
+ def search_by_dependency(dependency, base = nil)
110
+ @cache[dependency.hash] ||= begin
111
+ specs = specs_by_name(dependency.name) + (base || [])
112
+ found = specs.select do |spec|
113
+ if base # allow all platforms when searching from a lockfile
114
+ dependency.matches_spec?(spec)
115
+ else
116
+ dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform)
117
+ end
118
+ end
119
+
120
+ wants_prerelease = dependency.requirement.prerelease?
121
+ only_prerelease = specs.all? {|spec| spec.version.prerelease? }
122
+
123
+ unless wants_prerelease || only_prerelease
124
+ found.reject! { |spec| spec.version.prerelease? }
125
+ end
126
+
127
+ found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
128
+ end
129
+ end
130
+
110
131
  def search_by_spec(spec)
111
132
  specs_by_name(spec.name).select do |s|
112
133
  same_version?(s.version, spec.version) && Gem::Platform.new(s.platform) == Gem::Platform.new(spec.platform)
@@ -124,19 +145,5 @@ module Bundler
124
145
  dep.requirement.satisfied_by?(spec.version)
125
146
  end
126
147
 
127
- def search_by_dependency(dependency)
128
- @cache[dependency.hash] ||= begin
129
- specs = specs_by_name(dependency.name)
130
- found = specs.select { |spec| dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) }
131
-
132
- wants_prerelease = dependency.requirement.prerelease?
133
- only_prerelease = specs.all? {|spec| spec.version.prerelease? }
134
- unless wants_prerelease || only_prerelease
135
- found.reject! { |spec| spec.version.prerelease? }
136
- end
137
-
138
- found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
139
- end
140
- end
141
148
  end
142
149
  end
@@ -3,6 +3,10 @@ require 'rubygems/dependency_installer'
3
3
 
4
4
  module Bundler
5
5
  class Installer < Environment
6
+ class << self
7
+ attr_accessor :post_install_messages
8
+ end
9
+
6
10
  def self.install(root, definition, options = {})
7
11
  installer = new(root, definition)
8
12
  installer.run(options)
@@ -46,6 +50,7 @@ module Bundler
46
50
  # Must install gems in the order that the resolver provides
47
51
  # as dependencies might actually affect the installation of
48
52
  # the gem.
53
+ Installer.post_install_messages = {}
49
54
  specs.each do |spec|
50
55
  spec.source.fetch(spec) if spec.source.respond_to?(:fetch)
51
56
 
@@ -59,12 +59,13 @@ module Bundler
59
59
  private
60
60
 
61
61
  def method_missing(method, *args, &blk)
62
- if Gem::Specification.new.respond_to?(method)
63
- raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification
64
- @specification.send(method, *args, &blk)
65
- else
66
- super
67
- end
62
+ return super if method == :to_ary
63
+
64
+ raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification
65
+
66
+ return super unless respond_to?(method)
67
+
68
+ @specification.send(method, *args, &blk)
68
69
  end
69
70
 
70
71
  end
@@ -361,7 +361,7 @@ module Bundler
361
361
  d = dep.dep
362
362
  end
363
363
  index = @source_requirements[d.name] || @index
364
- results = index.search_for_all_platforms(d, @base[d.name])
364
+ results = index.search(d, @base[d.name])
365
365
 
366
366
  if results.any?
367
367
  version = results.first.version
@@ -19,7 +19,7 @@ module Gem
19
19
 
20
20
  def full_gem_path
21
21
  source.respond_to?(:path) ?
22
- Pathname.new(loaded_from).dirname.expand_path.to_s :
22
+ Pathname.new(loaded_from).dirname.expand_path(Bundler.root).to_s :
23
23
  rg_full_gem_path
24
24
  end
25
25