bundler 1.0.21 → 1.1.rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +7 -0
- data/CHANGELOG.md +153 -1
- data/README.md +3 -3
- data/Rakefile +15 -27
- data/bin/bundle +7 -0
- data/bundler.gemspec +1 -1
- data/lib/bundler/cli.rb +126 -45
- data/lib/bundler/definition.rb +22 -5
- data/lib/bundler/dep_proxy.rb +35 -0
- data/lib/bundler/dsl.rb +17 -34
- data/lib/bundler/endpoint_specification.rb +69 -0
- data/lib/bundler/fetcher.rb +221 -0
- data/lib/bundler/gem_helper.rb +0 -1
- data/lib/bundler/gem_helpers.rb +23 -0
- data/lib/bundler/index.rb +77 -38
- data/lib/bundler/installer.rb +43 -1
- data/lib/bundler/man/bundle-benchmark +19 -0
- data/lib/bundler/man/bundle-benchmark.txt +27 -0
- data/lib/bundler/man/bundle-config +1 -1
- data/lib/bundler/man/bundle-config.txt +3 -3
- data/lib/bundler/man/bundle-install +288 -0
- data/lib/bundler/man/bundle-install.txt +74 -79
- data/lib/bundler/man/bundle-package +1 -1
- data/lib/bundler/man/bundle-package.txt +1 -1
- data/lib/bundler/man/bundle-update +1 -1
- data/lib/bundler/man/bundle-update.txt +41 -41
- data/lib/bundler/man/gemfile.5 +6 -7
- data/lib/bundler/man/gemfile.5.txt +9 -9
- data/lib/bundler/match_platform.rb +13 -0
- data/lib/bundler/remote_specification.rb +6 -8
- data/lib/bundler/resolver.rb +32 -19
- data/lib/bundler/rubygems_ext.rb +2 -86
- data/lib/bundler/rubygems_integration.rb +35 -0
- data/lib/bundler/runtime.rb +84 -1
- data/lib/bundler/source.rb +85 -88
- data/lib/bundler/spec_set.rb +2 -0
- data/lib/bundler/templates/Executable +1 -1
- data/lib/bundler/templates/newgem/Gemfile.tt +1 -1
- data/lib/bundler/templates/newgem/Rakefile.tt +1 -0
- data/lib/bundler/templates/newgem/bin/newgem.tt +1 -1
- data/lib/bundler/templates/newgem/gitignore.tt +14 -1
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +13 -20
- data/lib/bundler/ui.rb +32 -17
- data/lib/bundler/vendor/net/http/faster.rb +27 -0
- data/lib/bundler/vendor/net/http/persistent.rb +468 -0
- data/lib/bundler/version.rb +1 -1
- data/lib/bundler.rb +56 -23
- data/man/bundle-install.ronn +7 -0
- data/man/bundle.ronn +3 -0
- data/man/gemfile.5.ronn +6 -6
- data/spec/bundler/dsl_spec.rb +22 -0
- data/spec/bundler/source_spec.rb +25 -0
- data/spec/install/deprecated_spec.rb +2 -3
- data/spec/install/gems/dependency_api_spec.rb +358 -0
- data/spec/install/gems/flex_spec.rb +1 -1
- data/spec/install/gems/groups_spec.rb +17 -8
- data/spec/install/gems/platform_spec.rb +16 -0
- data/spec/install/gems/post_install_spec.rb +47 -0
- data/spec/install/gems/simple_case_spec.rb +61 -64
- data/spec/install/gems/standalone_spec.rb +238 -0
- data/spec/install/git_spec.rb +62 -0
- data/spec/other/check_spec.rb +30 -0
- data/spec/other/clean_spec.rb +397 -0
- data/spec/other/exec_spec.rb +0 -29
- data/spec/other/newgem_spec.rb +39 -0
- data/spec/other/outdated_spec.rb +93 -0
- data/spec/other/show_spec.rb +6 -0
- data/spec/quality_spec.rb +1 -1
- data/spec/realworld/edgecases_spec.rb +12 -0
- data/spec/runtime/executable_spec.rb +10 -0
- data/spec/runtime/require_spec.rb +8 -9
- data/spec/runtime/with_clean_env_spec.rb +60 -7
- data/spec/spec_helper.rb +8 -1
- data/spec/support/artifice/endopint_marshal_fail_basic_authentication.rb +13 -0
- data/spec/support/artifice/endpoint.rb +54 -0
- data/spec/support/artifice/endpoint_500.rb +37 -0
- data/spec/support/artifice/endpoint_api_missing.rb +16 -0
- data/spec/support/artifice/endpoint_basic_authentication.rb +13 -0
- data/spec/support/artifice/endpoint_extra.rb +27 -0
- data/spec/support/artifice/endpoint_extra_missing.rb +15 -0
- data/spec/support/artifice/endpoint_fallback.rb +18 -0
- data/spec/support/artifice/endpoint_marshal_fail.rb +11 -0
- data/spec/support/artifice/endpoint_redirect.rb +15 -0
- data/spec/support/builders.rb +7 -0
- data/spec/support/fakeweb/rack-1.0.0.marshal +2 -0
- data/spec/support/fakeweb/windows.rb +23 -0
- data/spec/support/helpers.rb +36 -3
- data/spec/support/path.rb +2 -0
- data/spec/support/rubygems_ext.rb +3 -3
- metadata +48 -74
data/lib/bundler/dsl.rb
CHANGED
|
@@ -20,6 +20,8 @@ module Bundler
|
|
|
20
20
|
@env = nil
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
attr_accessor :dependencies
|
|
24
|
+
|
|
23
25
|
def gemspec(opts = nil)
|
|
24
26
|
path = opts && opts[:path] || '.'
|
|
25
27
|
name = opts && opts[:name] || '{,*}'
|
|
@@ -90,18 +92,18 @@ module Bundler
|
|
|
90
92
|
def source(source, options = {})
|
|
91
93
|
case source
|
|
92
94
|
when :gemcutter, :rubygems, :rubyforge then
|
|
93
|
-
rubygems_source "http://rubygems.org"
|
|
95
|
+
@rubygems_source.add_remote "http://rubygems.org"
|
|
94
96
|
return
|
|
95
97
|
when String
|
|
96
|
-
rubygems_source source
|
|
98
|
+
@rubygems_source.add_remote source
|
|
97
99
|
return
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
options[:prepend] ? @sources.unshift(@source) : @sources << @source
|
|
100
|
+
else
|
|
101
|
+
@source = source
|
|
102
|
+
options[:prepend] ? @sources.unshift(@source) : @sources << @source
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
yield if block_given?
|
|
105
|
+
return @source
|
|
106
|
+
end
|
|
105
107
|
ensure
|
|
106
108
|
@source = nil
|
|
107
109
|
end
|
|
@@ -126,8 +128,7 @@ module Bundler
|
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
def to_definition(lockfile, unlock)
|
|
129
|
-
@sources << @rubygems_source
|
|
130
|
-
@sources.uniq!
|
|
131
|
+
@sources << @rubygems_source unless @sources.include?(@rubygems_source)
|
|
131
132
|
Definition.new(lockfile, @dependencies, @sources, unlock)
|
|
132
133
|
end
|
|
133
134
|
|
|
@@ -168,21 +169,8 @@ module Bundler
|
|
|
168
169
|
end
|
|
169
170
|
end
|
|
170
171
|
|
|
171
|
-
deprecate :only, :group
|
|
172
|
-
deprecate :except
|
|
173
|
-
deprecate :disable_system_gems
|
|
174
|
-
deprecate :disable_rubygems
|
|
175
|
-
deprecate :clear_sources
|
|
176
|
-
deprecate :bundle_path
|
|
177
|
-
deprecate :bin_path
|
|
178
|
-
|
|
179
172
|
private
|
|
180
173
|
|
|
181
|
-
def rubygems_source(source)
|
|
182
|
-
@rubygems_source.add_remote source
|
|
183
|
-
@sources << @rubygems_source
|
|
184
|
-
end
|
|
185
|
-
|
|
186
174
|
def _normalize_hash(opts)
|
|
187
175
|
# Cannot modify a hash during an iteration in 1.9
|
|
188
176
|
opts.keys.each do |k|
|
|
@@ -197,7 +185,7 @@ module Bundler
|
|
|
197
185
|
def _normalize_options(name, version, opts)
|
|
198
186
|
_normalize_hash(opts)
|
|
199
187
|
|
|
200
|
-
invalid_keys = opts.keys - %w(group groups git path name branch ref tag require submodules platform platforms type)
|
|
188
|
+
invalid_keys = opts.keys - %w(group groups git github path name branch ref tag require submodules platform platforms type)
|
|
201
189
|
if invalid_keys.any?
|
|
202
190
|
plural = invalid_keys.size > 1
|
|
203
191
|
message = "You passed #{invalid_keys.map{|k| ':'+k }.join(", ")} "
|
|
@@ -223,7 +211,11 @@ module Bundler
|
|
|
223
211
|
raise DslError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
|
|
224
212
|
end
|
|
225
213
|
|
|
226
|
-
|
|
214
|
+
if github = opts.delete("github")
|
|
215
|
+
github = "#{github}/#{github}" unless github.include?("/")
|
|
216
|
+
opts["git"] = "git://github.com/#{github}.git"
|
|
217
|
+
end
|
|
218
|
+
|
|
227
219
|
["git", "path"].each do |type|
|
|
228
220
|
if param = opts[type]
|
|
229
221
|
if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/
|
|
@@ -243,15 +235,6 @@ module Bundler
|
|
|
243
235
|
end
|
|
244
236
|
|
|
245
237
|
def _deprecated_options(options)
|
|
246
|
-
if options.include?(:require_as)
|
|
247
|
-
raise DeprecatedError, "Please replace :require_as with :require"
|
|
248
|
-
elsif options.include?(:vendored_at)
|
|
249
|
-
raise DeprecatedError, "Please replace :vendored_at with :path"
|
|
250
|
-
elsif options.include?(:only)
|
|
251
|
-
raise DeprecatedError, "Please replace :only with :group"
|
|
252
|
-
elsif options.include?(:except)
|
|
253
|
-
raise DeprecatedError, "The :except option is no longer supported"
|
|
254
|
-
end
|
|
255
238
|
end
|
|
256
239
|
end
|
|
257
240
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
|
|
22
|
+
# needed for standalone, load required_paths from local gemspec
|
|
23
|
+
# after the gem in installed
|
|
24
|
+
def require_paths
|
|
25
|
+
if @remote_specification
|
|
26
|
+
@remote_specification.require_paths
|
|
27
|
+
elsif _local_specification
|
|
28
|
+
_local_specification.require_paths
|
|
29
|
+
else
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# needed for binstubs
|
|
35
|
+
def executables
|
|
36
|
+
if @remote_specification
|
|
37
|
+
@remote_specification.executables
|
|
38
|
+
elsif _local_specification
|
|
39
|
+
_local_specification.executables
|
|
40
|
+
else
|
|
41
|
+
super
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# needed for bundle clean
|
|
46
|
+
def bindir
|
|
47
|
+
if @remote_specification
|
|
48
|
+
@remote_specification.bindir
|
|
49
|
+
elsif _local_specification
|
|
50
|
+
_local_specification.bindir
|
|
51
|
+
else
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def _local_specification
|
|
57
|
+
eval(File.read(local_specification_path)) if @loaded_from && File.exists?(local_specification_path)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def __swap__(spec)
|
|
61
|
+
@remote_specification = spec
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
def local_specification_path
|
|
66
|
+
"#{base_dir}/specifications/#{full_name}.gemspec"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'net/http/persistent'
|
|
3
|
+
|
|
4
|
+
module Bundler
|
|
5
|
+
# Handles all the fetching with the rubygems server
|
|
6
|
+
class Fetcher
|
|
7
|
+
REDIRECT_LIMIT = 5
|
|
8
|
+
|
|
9
|
+
attr_reader :has_api
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :disable_endpoint
|
|
13
|
+
|
|
14
|
+
@@spec_fetch_map ||= {}
|
|
15
|
+
|
|
16
|
+
def fetch(spec)
|
|
17
|
+
spec, uri = @@spec_fetch_map[spec.full_name]
|
|
18
|
+
if spec
|
|
19
|
+
path = download_gem_from_uri(spec, uri)
|
|
20
|
+
s = Bundler.rubygems.spec_from_gem(path)
|
|
21
|
+
spec.__swap__(s)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def download_gem_from_uri(spec, uri)
|
|
26
|
+
spec.fetch_platform
|
|
27
|
+
|
|
28
|
+
download_path = Bundler.requires_sudo? ? Bundler.tmp : Bundler.rubygems.gem_dir
|
|
29
|
+
gem_path = "#{Bundler.rubygems.gem_dir}/cache/#{spec.full_name}.gem"
|
|
30
|
+
|
|
31
|
+
FileUtils.mkdir_p("#{download_path}/cache")
|
|
32
|
+
Bundler.rubygems.download_gem(spec, uri, download_path)
|
|
33
|
+
|
|
34
|
+
if Bundler.requires_sudo?
|
|
35
|
+
Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/cache"
|
|
36
|
+
Bundler.sudo "mv #{Bundler.tmp}/cache/#{spec.full_name}.gem #{gem_path}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
gem_path
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def initialize(remote_uri)
|
|
44
|
+
@remote_uri = remote_uri
|
|
45
|
+
@has_api = true # will be set to false if the rubygems index is ever fetched
|
|
46
|
+
@@connection ||= Net::HTTP::Persistent.new nil, :ENV
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# fetch a gem specification
|
|
50
|
+
def fetch_spec(spec)
|
|
51
|
+
spec = spec - [nil, 'ruby', '']
|
|
52
|
+
spec_file_name = "#{spec.join '-'}.gemspec.rz"
|
|
53
|
+
|
|
54
|
+
uri = URI.parse("#{@remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}")
|
|
55
|
+
|
|
56
|
+
spec_rz = (uri.scheme == "file") ? Gem.read_binary(uri.path) : fetch(uri)
|
|
57
|
+
Marshal.load Gem.inflate(spec_rz)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# return the specs in the bundler format as an index
|
|
61
|
+
def specs(gem_names, source)
|
|
62
|
+
index = Index.new
|
|
63
|
+
|
|
64
|
+
if !gem_names || @remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
|
|
65
|
+
Bundler.ui.info "Fetching source index from #{strip_user_pass_from_uri(@remote_uri)}"
|
|
66
|
+
specs = fetch_all_remote_specs
|
|
67
|
+
else
|
|
68
|
+
Bundler.ui.info "Fetching gem metadata from #{strip_user_pass_from_uri(@remote_uri)}", Bundler.ui.debug?
|
|
69
|
+
begin
|
|
70
|
+
specs = fetch_remote_specs(gem_names)
|
|
71
|
+
# fall back to the legacy index in the following cases
|
|
72
|
+
# 1. Gemcutter Endpoint doesn't return a 200
|
|
73
|
+
# 2. Marshal blob doesn't load properly
|
|
74
|
+
# 3. One of the YAML gemspecs has the Syck::DefaultKey problem
|
|
75
|
+
rescue HTTPError, TypeError => e
|
|
76
|
+
# new line now that the dots are over
|
|
77
|
+
Bundler.ui.info "" unless Bundler.ui.debug?
|
|
78
|
+
|
|
79
|
+
if @remote_uri.to_s.include?("rubygems.org")
|
|
80
|
+
Bundler.ui.info "Error #{e.class} during request to dependency API"
|
|
81
|
+
end
|
|
82
|
+
Bundler.ui.debug e.message
|
|
83
|
+
Bundler.ui.debug e.backtrace
|
|
84
|
+
|
|
85
|
+
Bundler.ui.info "Fetching full source index from #{strip_user_pass_from_uri(@remote_uri)}"
|
|
86
|
+
specs = fetch_all_remote_specs
|
|
87
|
+
else
|
|
88
|
+
# new line now that the dots are over
|
|
89
|
+
Bundler.ui.info "" unless Bundler.ui.debug?
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
specs[@remote_uri].each do |name, version, platform, dependencies|
|
|
94
|
+
next if name == 'bundler'
|
|
95
|
+
spec = nil
|
|
96
|
+
if dependencies
|
|
97
|
+
spec = EndpointSpecification.new(name, version, platform, dependencies)
|
|
98
|
+
else
|
|
99
|
+
spec = RemoteSpecification.new(name, version, platform, self)
|
|
100
|
+
end
|
|
101
|
+
spec.source = source
|
|
102
|
+
@@spec_fetch_map[spec.full_name] = [spec, @remote_uri]
|
|
103
|
+
index << spec
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
index
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# fetch index
|
|
110
|
+
def fetch_remote_specs(gem_names, full_dependency_list = [], last_spec_list = [])
|
|
111
|
+
query_list = gem_names - full_dependency_list
|
|
112
|
+
|
|
113
|
+
# only display the message on the first run
|
|
114
|
+
if Bundler.ui.debug?
|
|
115
|
+
Bundler.ui.debug "Query List: #{query_list.inspect}"
|
|
116
|
+
else
|
|
117
|
+
Bundler.ui.info ".", false
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
return {@remote_uri => last_spec_list} if query_list.empty?
|
|
121
|
+
|
|
122
|
+
spec_list, deps_list = fetch_dependency_remote_specs(query_list)
|
|
123
|
+
returned_gems = spec_list.map {|spec| spec.first }.uniq
|
|
124
|
+
|
|
125
|
+
fetch_remote_specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def fetch(uri, counter = 0)
|
|
131
|
+
raise HTTPError, "Too many redirects" if counter >= REDIRECT_LIMIT
|
|
132
|
+
|
|
133
|
+
begin
|
|
134
|
+
Bundler.ui.debug "Fetching from: #{uri}"
|
|
135
|
+
response = @@connection.request(uri)
|
|
136
|
+
rescue SocketError, Timeout, Net::HTTP::Persistent::Error
|
|
137
|
+
raise Bundler::HTTPError, "Network error while fetching #{uri}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
case response
|
|
141
|
+
when Net::HTTPRedirection
|
|
142
|
+
Bundler.ui.debug("HTTP Redirection")
|
|
143
|
+
new_uri = URI.parse(response["location"])
|
|
144
|
+
new_uri.user = uri.user
|
|
145
|
+
new_uri.password = uri.password
|
|
146
|
+
fetch(new_uri, counter + 1)
|
|
147
|
+
when Net::HTTPSuccess
|
|
148
|
+
Bundler.ui.debug("HTTP Success")
|
|
149
|
+
response.body
|
|
150
|
+
else
|
|
151
|
+
Bundler.ui.debug("HTTP Error")
|
|
152
|
+
raise HTTPError
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# fetch from Gemcutter Dependency Endpoint API
|
|
157
|
+
def fetch_dependency_remote_specs(gem_names)
|
|
158
|
+
Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(' ')}"
|
|
159
|
+
uri = URI.parse("#{@remote_uri}api/v1/dependencies?gems=#{gem_names.join(",")}")
|
|
160
|
+
marshalled_deps = fetch(uri)
|
|
161
|
+
gem_list = Marshal.load(marshalled_deps)
|
|
162
|
+
deps_list = []
|
|
163
|
+
|
|
164
|
+
spec_list = gem_list.map do |s|
|
|
165
|
+
dependencies = s[:dependencies].map do |d|
|
|
166
|
+
begin
|
|
167
|
+
name, requirement = d
|
|
168
|
+
dep = Gem::Dependency.new(name, requirement.split(", "))
|
|
169
|
+
rescue ArgumentError => e
|
|
170
|
+
if e.message.include?('Illformed requirement ["#<YAML::Syck::DefaultKey')
|
|
171
|
+
puts # we shouldn't print the error message on the "fetching info" status line
|
|
172
|
+
raise GemspecError, %{Unfortunately, the gem #{s[:name]} (#{s[:number]}) } +
|
|
173
|
+
%{has an invalid gemspec. As a result, Bundler cannot install this Gemfile. } +
|
|
174
|
+
%{Please ask the gem author to yank the bad version to fix this issue. For } +
|
|
175
|
+
%{more information, see http://bit.ly/illformed-requirement.}
|
|
176
|
+
else
|
|
177
|
+
raise e
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
deps_list << dep.name
|
|
182
|
+
|
|
183
|
+
dep
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
[s[:name], Gem::Version.new(s[:number]), s[:platform], dependencies]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
[spec_list, deps_list.uniq]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# fetch from modern index: specs.4.8.gz
|
|
193
|
+
def fetch_all_remote_specs
|
|
194
|
+
@has_api = false
|
|
195
|
+
Gem.sources = ["#{@remote_uri}"]
|
|
196
|
+
spec_list = Hash.new { |h,k| h[k] = [] }
|
|
197
|
+
begin
|
|
198
|
+
# Fetch all specs, minus prerelease specs
|
|
199
|
+
spec_list = Gem::SpecFetcher.new.list(true, false)
|
|
200
|
+
# Then fetch the prerelease specs
|
|
201
|
+
begin
|
|
202
|
+
Gem::SpecFetcher.new.list(false, true).each {|k, v| spec_list[k] += v }
|
|
203
|
+
rescue Gem::RemoteFetcher::FetchError
|
|
204
|
+
Bundler.ui.debug "Could not fetch prerelease specs from #{strip_user_pass_from_uri(@remote_uri)}"
|
|
205
|
+
end
|
|
206
|
+
rescue Gem::RemoteFetcher::FetchError
|
|
207
|
+
raise Bundler::HTTPError, "Could not reach #{strip_user_pass_from_uri(@remote_uri)}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
return spec_list
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def strip_user_pass_from_uri(uri)
|
|
214
|
+
uri_dup = uri.dup
|
|
215
|
+
uri_dup.user = "****" if uri_dup.user
|
|
216
|
+
uri_dup.password = "****" if uri_dup.password
|
|
217
|
+
|
|
218
|
+
uri_dup
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/bundler/gem_helper.rb
CHANGED
|
@@ -42,7 +42,6 @@ module Bundler
|
|
|
42
42
|
def build_gem
|
|
43
43
|
file_name = nil
|
|
44
44
|
sh("gem build -V '#{spec_path}'") { |out, code|
|
|
45
|
-
raise out unless out[/Successfully/]
|
|
46
45
|
file_name = File.basename(built_gem_path)
|
|
47
46
|
FileUtils.mkdir_p(File.join(base, 'pkg'))
|
|
48
47
|
FileUtils.mv(built_gem_path, 'pkg')
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Bundler
|
|
2
|
+
module GemHelpers
|
|
3
|
+
|
|
4
|
+
GENERIC_CACHE = {}
|
|
5
|
+
GENERICS = [
|
|
6
|
+
Gem::Platform.new('java'),
|
|
7
|
+
Gem::Platform.new('mswin32'),
|
|
8
|
+
Gem::Platform.new('x86-mingw32'),
|
|
9
|
+
Gem::Platform::RUBY
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
def generic(p)
|
|
13
|
+
return p if p == Gem::Platform::RUBY
|
|
14
|
+
|
|
15
|
+
GENERIC_CACHE[p] ||= begin
|
|
16
|
+
found = GENERICS.find do |p2|
|
|
17
|
+
p2.is_a?(Gem::Platform) && p.os == p2.os
|
|
18
|
+
end
|
|
19
|
+
found || Gem::Platform::RUBY
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/bundler/index.rb
CHANGED
|
@@ -8,16 +8,18 @@ module Bundler
|
|
|
8
8
|
i
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
attr_reader :specs
|
|
11
|
+
attr_reader :specs, :sources
|
|
12
12
|
protected :specs
|
|
13
13
|
|
|
14
14
|
def initialize
|
|
15
|
+
@sources = []
|
|
15
16
|
@cache = {}
|
|
16
17
|
@specs = Hash.new { |h,k| h[k] = [] }
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def initialize_copy(o)
|
|
20
21
|
super
|
|
22
|
+
@sources = @sources.dup
|
|
21
23
|
@cache = {}
|
|
22
24
|
@specs = Hash.new { |h,k| h[k] = [] }
|
|
23
25
|
|
|
@@ -26,43 +28,43 @@ module Bundler
|
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
30
|
|
|
31
|
+
def inspect
|
|
32
|
+
"<Index sources=#{sources.map{|s| s.inspect}} specs.size=#{specs.size}>"
|
|
33
|
+
end
|
|
34
|
+
|
|
29
35
|
def empty?
|
|
30
36
|
each { return false }
|
|
31
37
|
true
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
# Search this index's specs, and any source indexes that this index knows
|
|
41
|
+
# about, returning all of the results.
|
|
42
|
+
def search(query, base = nil)
|
|
43
|
+
results = local_search(query, base)
|
|
44
|
+
@sources.each do |source|
|
|
45
|
+
results += source.search(query, base)
|
|
39
46
|
end
|
|
47
|
+
results
|
|
40
48
|
end
|
|
41
49
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
unless wants_prerelease || only_prerelease
|
|
50
|
-
found.reject! { |spec| spec.version.prerelease? }
|
|
50
|
+
def local_search(query, base = nil)
|
|
51
|
+
case query
|
|
52
|
+
when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
|
|
53
|
+
when String then specs_by_name(query)
|
|
54
|
+
when Gem::Dependency then search_by_dependency(query, base)
|
|
55
|
+
else
|
|
56
|
+
raise "You can't search for a #{query.inspect}."
|
|
51
57
|
end
|
|
52
|
-
|
|
53
|
-
found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
|
|
54
58
|
end
|
|
55
59
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
specs.map{|s| s.source.class }
|
|
59
|
-
end.flatten.uniq
|
|
60
|
+
def source_types
|
|
61
|
+
sources.map{|s| s.class }.uniq
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
alias [] search
|
|
63
65
|
|
|
64
66
|
def <<(spec)
|
|
65
|
-
arr =
|
|
67
|
+
arr = specs_by_name(spec.name)
|
|
66
68
|
|
|
67
69
|
arr.delete_if do |s|
|
|
68
70
|
same_version?(s.version, spec.version) && s.platform == spec.platform
|
|
@@ -73,11 +75,21 @@ module Bundler
|
|
|
73
75
|
end
|
|
74
76
|
|
|
75
77
|
def each(&blk)
|
|
76
|
-
|
|
78
|
+
specs.values.each do |specs|
|
|
77
79
|
specs.each(&blk)
|
|
78
80
|
end
|
|
79
81
|
end
|
|
80
82
|
|
|
83
|
+
# returns a list of the dependencies
|
|
84
|
+
def unmet_dependency_names
|
|
85
|
+
dependency_names = specs.values.map do |array_of_s|
|
|
86
|
+
array_of_s.map do |s|
|
|
87
|
+
s.dependencies.map{|d| d.name }
|
|
88
|
+
end
|
|
89
|
+
end.flatten.uniq
|
|
90
|
+
dependency_names.select{|name| specs_by_name(name).empty? }
|
|
91
|
+
end
|
|
92
|
+
|
|
81
93
|
def use(other, override_dupes = false)
|
|
82
94
|
return unless other
|
|
83
95
|
other.each do |s|
|
|
@@ -90,16 +102,57 @@ module Bundler
|
|
|
90
102
|
self
|
|
91
103
|
end
|
|
92
104
|
|
|
105
|
+
def size
|
|
106
|
+
@sources.inject(@specs.size) do |size, source|
|
|
107
|
+
size += source.size
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
93
111
|
def ==(o)
|
|
94
112
|
all? do |s|
|
|
95
113
|
s2 = o[s].first and (s.dependencies & s2.dependencies).empty?
|
|
96
114
|
end
|
|
97
115
|
end
|
|
98
116
|
|
|
117
|
+
def add_source(index)
|
|
118
|
+
if index.is_a?(Index)
|
|
119
|
+
@sources << index
|
|
120
|
+
@sources.uniq! # need to use uniq! here instead of checking for the item before adding
|
|
121
|
+
else
|
|
122
|
+
raise ArgumentError, "Source must be an index, not #{index.class}"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
99
126
|
private
|
|
100
127
|
|
|
128
|
+
def specs_by_name(name)
|
|
129
|
+
@specs[name]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def search_by_dependency(dependency, base = nil)
|
|
133
|
+
@cache[dependency.hash^base.hash] ||= begin
|
|
134
|
+
specs = specs_by_name(dependency.name) + (base || [])
|
|
135
|
+
found = specs.select do |spec|
|
|
136
|
+
if base # allow all platforms when searching from a lockfile
|
|
137
|
+
dependency.matches_spec?(spec)
|
|
138
|
+
else
|
|
139
|
+
dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
wants_prerelease = dependency.requirement.prerelease?
|
|
144
|
+
only_prerelease = specs.all? {|spec| spec.version.prerelease? }
|
|
145
|
+
|
|
146
|
+
unless wants_prerelease || only_prerelease
|
|
147
|
+
found.reject! { |spec| spec.version.prerelease? }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
101
154
|
def search_by_spec(spec)
|
|
102
|
-
|
|
155
|
+
specs_by_name(spec.name).select do |s|
|
|
103
156
|
same_version?(s.version, spec.version) && Gem::Platform.new(s.platform) == Gem::Platform.new(spec.platform)
|
|
104
157
|
end
|
|
105
158
|
end
|
|
@@ -120,19 +173,5 @@ module Bundler
|
|
|
120
173
|
dep.requirement.satisfied_by?(spec.version)
|
|
121
174
|
end
|
|
122
175
|
|
|
123
|
-
def search_by_dependency(dependency)
|
|
124
|
-
@cache[dependency.hash] ||= begin
|
|
125
|
-
specs = @specs[dependency.name]
|
|
126
|
-
found = specs.select { |spec| dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) }
|
|
127
|
-
|
|
128
|
-
wants_prerelease = dependency.requirement.prerelease?
|
|
129
|
-
only_prerelease = specs.all? {|spec| spec.version.prerelease? }
|
|
130
|
-
unless wants_prerelease || only_prerelease
|
|
131
|
-
found.reject! { |spec| spec.version.prerelease? }
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
176
|
end
|
|
138
177
|
end
|
data/lib/bundler/installer.rb
CHANGED
|
@@ -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)
|
|
@@ -24,6 +28,7 @@ module Bundler
|
|
|
24
28
|
|
|
25
29
|
if dependencies.empty?
|
|
26
30
|
Bundler.ui.warn "The Gemfile specifies no dependencies"
|
|
31
|
+
lock
|
|
27
32
|
return
|
|
28
33
|
end
|
|
29
34
|
|
|
@@ -46,11 +51,13 @@ module Bundler
|
|
|
46
51
|
# Must install gems in the order that the resolver provides
|
|
47
52
|
# as dependencies might actually affect the installation of
|
|
48
53
|
# the gem.
|
|
54
|
+
Installer.post_install_messages = {}
|
|
49
55
|
specs.each do |spec|
|
|
50
56
|
install_gem_from_spec(spec)
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
lock
|
|
60
|
+
generate_standalone(options[:standalone]) if options[:standalone]
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
private
|
|
@@ -58,7 +65,7 @@ module Bundler
|
|
|
58
65
|
def install_gem_from_spec(spec)
|
|
59
66
|
# Download the gem to get the spec, because some specs that are returned
|
|
60
67
|
# by rubygems.org are broken and wrong.
|
|
61
|
-
|
|
68
|
+
Bundler::Fetcher.fetch(spec) if spec.source.is_a?(Bundler::Source::Rubygems)
|
|
62
69
|
|
|
63
70
|
# Fetch the build settings, if there are any
|
|
64
71
|
settings = Bundler.settings["build.#{spec.name}"]
|
|
@@ -72,6 +79,10 @@ module Bundler
|
|
|
72
79
|
generate_bundler_executable_stubs(spec) if Bundler.settings[:bin]
|
|
73
80
|
FileUtils.rm_rf(Bundler.tmp)
|
|
74
81
|
rescue Exception => e
|
|
82
|
+
# install hook failed
|
|
83
|
+
raise e if e.is_a?(Gem::InstallError)
|
|
84
|
+
|
|
85
|
+
# other failure, likely a native extension build failure
|
|
75
86
|
Bundler.ui.info ""
|
|
76
87
|
Bundler.ui.warn "#{e.class}: #{e.message}"
|
|
77
88
|
msg = "An error occured while installing #{spec.name} (#{spec.version}),"
|
|
@@ -93,5 +104,36 @@ module Bundler
|
|
|
93
104
|
end
|
|
94
105
|
end
|
|
95
106
|
end
|
|
107
|
+
|
|
108
|
+
def generate_standalone(groups)
|
|
109
|
+
standalone_path = Bundler.settings[:path]
|
|
110
|
+
bundler_path = File.join(standalone_path, "bundler")
|
|
111
|
+
FileUtils.mkdir_p(bundler_path)
|
|
112
|
+
|
|
113
|
+
paths = []
|
|
114
|
+
|
|
115
|
+
if groups.empty?
|
|
116
|
+
specs = Bundler.definition.requested_specs
|
|
117
|
+
else
|
|
118
|
+
specs = Bundler.definition.specs_for groups.map { |g| g.to_sym }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
specs.each do |spec|
|
|
122
|
+
next if spec.name == "bundler"
|
|
123
|
+
|
|
124
|
+
spec.require_paths.each do |path|
|
|
125
|
+
full_path = File.join(spec.full_gem_path, path)
|
|
126
|
+
paths << Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path))
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
File.open File.join(bundler_path, "setup.rb"), "w" do |file|
|
|
132
|
+
file.puts "path = File.expand_path('..', __FILE__)"
|
|
133
|
+
paths.each do |path|
|
|
134
|
+
file.puts %{$:.unshift File.expand_path("\#{path}/#{path}")}
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
96
138
|
end
|
|
97
139
|
end
|