bowline-bundler 0.0.1
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/LICENSE +20 -0
- data/README.markdown +291 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/bowline-bundle +59 -0
- data/lib/bowline/bundler/bundle.rb +323 -0
- data/lib/bowline/bundler/cli.rb +87 -0
- data/lib/bowline/bundler/dependency.rb +62 -0
- data/lib/bowline/bundler/dsl.rb +182 -0
- data/lib/bowline/bundler/environment.rb +87 -0
- data/lib/bowline/bundler/finder.rb +51 -0
- data/lib/bowline/bundler/gem_bundle.rb +11 -0
- data/lib/bowline/bundler/gem_ext.rb +34 -0
- data/lib/bowline/bundler/remote_specification.rb +53 -0
- data/lib/bowline/bundler/resolver.rb +250 -0
- data/lib/bowline/bundler/runtime.rb +2 -0
- data/lib/bowline/bundler/source.rb +361 -0
- data/lib/bowline/bundler/templates/app_script.erb +3 -0
- data/lib/bowline/bundler/templates/environment.erb +156 -0
- data/lib/bowline/bundler/templates/environment_picker.erb +4 -0
- data/lib/bowline/bundler.rb +35 -0
- data/spec/bundler/cli_spec.rb +558 -0
- data/spec/bundler/directory_spec.rb +255 -0
- data/spec/bundler/dsl_spec.rb +126 -0
- data/spec/bundler/fetcher_spec.rb +138 -0
- data/spec/bundler/git_spec.rb +266 -0
- data/spec/bundler/installer_spec.rb +155 -0
- data/spec/bundler/manifest_file_spec.rb +105 -0
- data/spec/bundler/manifest_spec.rb +257 -0
- data/spec/bundler/runtime_spec.rb +141 -0
- data/spec/bundler/system_gems_spec.rb +42 -0
- data/spec/quality_spec.rb +57 -0
- data/spec/resolver/engine_spec.rb +112 -0
- data/spec/resolver/error_spec.rb +50 -0
- data/spec/resolver/fake_source_index_spec.rb +43 -0
- data/spec/resolver/prerelease_spec.rb +113 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/builders.rb +257 -0
- data/spec/support/core_ext.rb +18 -0
- data/spec/support/helpers.rb +126 -0
- data/spec/support/matchers.rb +201 -0
- data/spec/support/path_utils.rb +63 -0
- metadata +126 -0
@@ -0,0 +1,323 @@
|
|
1
|
+
module Bundler
|
2
|
+
class InvalidRepository < StandardError ; end
|
3
|
+
|
4
|
+
class Bundle
|
5
|
+
attr_reader :gemfile, :environment
|
6
|
+
|
7
|
+
def self.load(gemfile = nil)
|
8
|
+
gemfile = Pathname.new(gemfile || default_gemfile).expand_path
|
9
|
+
|
10
|
+
unless gemfile.file?
|
11
|
+
raise ManifestFileNotFound, "Manifest file not found: #{gemfile.to_s.inspect}"
|
12
|
+
end
|
13
|
+
|
14
|
+
new(gemfile)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.default_gemfile
|
18
|
+
current = Pathname.new(Dir.pwd)
|
19
|
+
|
20
|
+
until current.root?
|
21
|
+
filename = current.join("Gemfile")
|
22
|
+
return filename if filename.exist?
|
23
|
+
current = current.parent
|
24
|
+
end
|
25
|
+
|
26
|
+
raise DefaultManifestNotFound
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO: passing in the filename is not good
|
30
|
+
def initialize(gemfile)
|
31
|
+
@gemfile = gemfile
|
32
|
+
@environment = Environment.new(self)
|
33
|
+
Dsl.evaluate(gemfile, self, @environment)
|
34
|
+
|
35
|
+
# path = env.gem_path
|
36
|
+
|
37
|
+
FileUtils.mkdir_p(gem_path)
|
38
|
+
|
39
|
+
@cache_path = gem_path.join('cache')
|
40
|
+
@cache = GemDirectorySource.new(self, :location => @cache_path)
|
41
|
+
|
42
|
+
@specs_path = gem_path.join('specifications')
|
43
|
+
@gems_path = gem_path.join('gems')
|
44
|
+
end
|
45
|
+
|
46
|
+
def root
|
47
|
+
gemfile.parent
|
48
|
+
end
|
49
|
+
|
50
|
+
def path
|
51
|
+
@path ||= root.join("vendor/gems")
|
52
|
+
end
|
53
|
+
|
54
|
+
def path=(path)
|
55
|
+
@path = (path.relative? ? root.join(path) : path).expand_path
|
56
|
+
end
|
57
|
+
|
58
|
+
def gem_path
|
59
|
+
path.join("#{Gem.ruby_engine}/#{Gem::ConfigMap[:ruby_version]}")
|
60
|
+
end
|
61
|
+
|
62
|
+
def bindir
|
63
|
+
@bindir ||= root.join("bin")
|
64
|
+
end
|
65
|
+
|
66
|
+
def bindir=(path)
|
67
|
+
@bindir = (path.relative? ? root.join(path) : path).expand_path
|
68
|
+
end
|
69
|
+
|
70
|
+
def install(options = {})
|
71
|
+
dependencies = @environment.dependencies
|
72
|
+
sources = @environment.sources
|
73
|
+
|
74
|
+
# ========== from env
|
75
|
+
if only_envs = options[:only]
|
76
|
+
dependencies.reject! { |d| !only_envs.any? {|env| d.in?(env) } }
|
77
|
+
end
|
78
|
+
# ==========
|
79
|
+
|
80
|
+
# TODO: clean this up
|
81
|
+
sources.each do |s|
|
82
|
+
s.local = options[:cached]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check to see whether the existing cache meets all the requirements
|
86
|
+
begin
|
87
|
+
valid = nil
|
88
|
+
# valid = Resolver.resolve(dependencies, [source_index], source_requirements)
|
89
|
+
rescue Bundler::GemNotFound
|
90
|
+
end
|
91
|
+
|
92
|
+
sources = only_local(sources) if options[:cached]
|
93
|
+
|
94
|
+
# Check the remote sources if the existing cache does not meet the requirements
|
95
|
+
# or the user passed --update
|
96
|
+
if options[:update] || !valid
|
97
|
+
Bundler.logger.info "Calculating dependencies..."
|
98
|
+
bundle = Resolver.resolve(dependencies, [@cache] + sources)
|
99
|
+
download(bundle, options)
|
100
|
+
do_install(bundle, options)
|
101
|
+
valid = bundle
|
102
|
+
end
|
103
|
+
|
104
|
+
generate_bins(valid, options)
|
105
|
+
cleanup(valid, options)
|
106
|
+
configure(valid, options)
|
107
|
+
|
108
|
+
Bundler.logger.info "Done."
|
109
|
+
end
|
110
|
+
|
111
|
+
def cache(*gemfiles)
|
112
|
+
FileUtils.mkdir_p(@cache_path)
|
113
|
+
gemfiles.each do |gemfile|
|
114
|
+
Bundler.logger.info "Caching: #{File.basename(gemfile)}"
|
115
|
+
FileUtils.cp(gemfile, @cache_path)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def list_outdated(options={})
|
120
|
+
outdated_gems = source_index.outdated.sort
|
121
|
+
|
122
|
+
if outdated_gems.empty?
|
123
|
+
Bundler.logger.info "All gems are up to date."
|
124
|
+
else
|
125
|
+
Bundler.logger.info "Outdated gems:"
|
126
|
+
outdated_gems.each do |name|
|
127
|
+
Bundler.logger.info " * #{name}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def prune(options = {})
|
133
|
+
dependencies, sources = @environment.gem_dependencies, @environment.sources
|
134
|
+
|
135
|
+
sources.each do |s|
|
136
|
+
s.local = true
|
137
|
+
end
|
138
|
+
|
139
|
+
sources = only_local(sources)
|
140
|
+
bundle = Resolver.resolve(dependencies, [@cache] + sources)
|
141
|
+
@cache.gems.each do |name, specs|
|
142
|
+
specs.each do |spec|
|
143
|
+
unless bundle.any? { |s| s.name == spec.name && s.version == spec.version }
|
144
|
+
Bundler.logger.info "Pruning #{spec.name} (#{spec.version}) from the cache"
|
145
|
+
FileUtils.rm @cache_path.join("#{spec.full_name}.gem")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def list(options = {})
|
152
|
+
Bundler.logger.info "Currently bundled gems:"
|
153
|
+
gems.each do |spec|
|
154
|
+
Bundler.logger.info " * #{spec.name} (#{spec.version})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def gems
|
159
|
+
source_index.gems.values
|
160
|
+
end
|
161
|
+
|
162
|
+
def source_index
|
163
|
+
index = Gem::SourceIndex.from_gems_in(@specs_path)
|
164
|
+
index.each { |n, spec| spec.loaded_from = @specs_path.join("#{spec.full_name}.gemspec") }
|
165
|
+
index
|
166
|
+
end
|
167
|
+
|
168
|
+
def download_path_for(type)
|
169
|
+
@repos[type].download_path_for
|
170
|
+
end
|
171
|
+
|
172
|
+
def setup_environment
|
173
|
+
unless @environment.system_gems
|
174
|
+
ENV["GEM_HOME"] = gem_path
|
175
|
+
ENV["GEM_PATH"] = gem_path
|
176
|
+
end
|
177
|
+
ENV["PATH"] = "#{bindir}:#{ENV["PATH"]}"
|
178
|
+
ENV["RUBYOPT"] = "-r#{gem_path}/environment #{ENV["RUBYOPT"]}"
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def only_local(sources)
|
184
|
+
sources.select { |s| s.can_be_local? }
|
185
|
+
end
|
186
|
+
|
187
|
+
def download(bundle, options)
|
188
|
+
bundle.sort_by {|s| s.full_name.downcase }.each do |spec|
|
189
|
+
next if spec.no_bundle?
|
190
|
+
spec.source.download(spec)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def do_install(bundle, options)
|
195
|
+
bundle.each do |spec|
|
196
|
+
next if spec.no_bundle?
|
197
|
+
spec.loaded_from = @specs_path.join("#{spec.full_name}.gemspec")
|
198
|
+
# Do nothing if the gem is already expanded
|
199
|
+
next if @gems_path.join(spec.full_name).directory?
|
200
|
+
|
201
|
+
case spec.source
|
202
|
+
when GemSource, GemDirectorySource, SystemGemSource
|
203
|
+
expand_gemfile(spec, options)
|
204
|
+
else
|
205
|
+
expand_vendored_gem(spec, options)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def generate_bins(bundle, options)
|
211
|
+
bundle.each do |spec|
|
212
|
+
next if spec.no_bundle?
|
213
|
+
# HAX -- Generate the bin
|
214
|
+
bin_dir = bindir
|
215
|
+
path = gem_path
|
216
|
+
gems_path = @gems_path
|
217
|
+
installer = Gem::Installer.allocate
|
218
|
+
installer.instance_eval do
|
219
|
+
@spec = spec
|
220
|
+
@bin_dir = bin_dir
|
221
|
+
@gem_dir = gems_path.join(spec.full_name)
|
222
|
+
@gem_home = path
|
223
|
+
@wrappers = true
|
224
|
+
@format_executable = false
|
225
|
+
@env_shebang = false
|
226
|
+
end
|
227
|
+
installer.generate_bin
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def expand_gemfile(spec, options)
|
232
|
+
Bundler.logger.info "Installing #{spec.name} (#{spec.version})"
|
233
|
+
|
234
|
+
gemfile = @cache_path.join("#{spec.full_name}.gem").to_s
|
235
|
+
|
236
|
+
if build_args = options[:build_options] && options[:build_options][spec.name]
|
237
|
+
Gem::Command.build_args = build_args.map {|k,v| "--with-#{k}=#{v}"}
|
238
|
+
end
|
239
|
+
|
240
|
+
installer = Gem::Installer.new(gemfile, options.merge(
|
241
|
+
:install_dir => gem_path,
|
242
|
+
:ignore_dependencies => true,
|
243
|
+
:env_shebang => true,
|
244
|
+
:wrappers => true,
|
245
|
+
:bin_dir => bindir
|
246
|
+
))
|
247
|
+
installer.install
|
248
|
+
rescue Gem::InstallError
|
249
|
+
cleanup_spec(spec)
|
250
|
+
raise
|
251
|
+
ensure
|
252
|
+
Gem::Command.build_args = []
|
253
|
+
end
|
254
|
+
|
255
|
+
def expand_vendored_gem(spec, options)
|
256
|
+
add_spec(spec)
|
257
|
+
FileUtils.mkdir_p(@gems_path)
|
258
|
+
File.symlink(spec.location, @gems_path.join(spec.full_name))
|
259
|
+
end
|
260
|
+
|
261
|
+
def add_spec(spec)
|
262
|
+
destination = @specs_path
|
263
|
+
destination.mkdir unless destination.exist?
|
264
|
+
|
265
|
+
File.open(destination.join("#{spec.full_name}.gemspec"), 'w') do |f|
|
266
|
+
f.puts spec.to_ruby
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def cleanup(valid, options)
|
271
|
+
to_delete = gems
|
272
|
+
to_delete.delete_if do |spec|
|
273
|
+
valid.any? { |other| spec.name == other.name && spec.version == other.version }
|
274
|
+
end
|
275
|
+
|
276
|
+
valid_executables = valid.map { |s| s.executables }.flatten.compact
|
277
|
+
|
278
|
+
to_delete.each do |spec|
|
279
|
+
Bundler.logger.info "Deleting gem: #{spec.name} (#{spec.version})"
|
280
|
+
cleanup_spec(spec)
|
281
|
+
# Cleanup the bin directory
|
282
|
+
spec.executables.each do |bin|
|
283
|
+
next if valid_executables.include?(bin)
|
284
|
+
Bundler.logger.info "Deleting bin file: #{bin}"
|
285
|
+
FileUtils.rm_rf(bindir.join(bin))
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def cleanup_spec(spec)
|
291
|
+
FileUtils.rm_rf(@specs_path.join("#{spec.full_name}.gemspec"))
|
292
|
+
FileUtils.rm_rf(@gems_path.join(spec.full_name))
|
293
|
+
end
|
294
|
+
|
295
|
+
def expand(options)
|
296
|
+
each_repo do |repo|
|
297
|
+
repo.expand(options)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def configure(specs, options)
|
302
|
+
FileUtils.mkdir_p(gem_path)
|
303
|
+
|
304
|
+
File.open(gem_path.join("environment.rb"), "w") do |file|
|
305
|
+
file.puts @environment.environment_rb(specs, options)
|
306
|
+
end
|
307
|
+
|
308
|
+
generate_environment_picker
|
309
|
+
end
|
310
|
+
|
311
|
+
def generate_environment_picker
|
312
|
+
FileUtils.cp("#{File.dirname(__FILE__)}/templates/environment_picker.erb", path.join("environment.rb"))
|
313
|
+
end
|
314
|
+
|
315
|
+
def require_code(file, dep)
|
316
|
+
constraint = case
|
317
|
+
when dep.only then %{ if #{dep.only.inspect}.include?(env)}
|
318
|
+
when dep.except then %{ unless #{dep.except.inspect}.include?(env)}
|
319
|
+
end
|
320
|
+
"require #{file.inspect}#{constraint}"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class CLI
|
5
|
+
def self.run(command, options = {})
|
6
|
+
new(options).run(command)
|
7
|
+
rescue DefaultManifestNotFound => e
|
8
|
+
Bundler.logger.error "Could not find a Gemfile to use"
|
9
|
+
exit 3
|
10
|
+
rescue InvalidEnvironmentName => e
|
11
|
+
Bundler.logger.error "Gemfile error: #{e.message}"
|
12
|
+
exit 4
|
13
|
+
rescue InvalidRepository => e
|
14
|
+
Bundler.logger.error e.message
|
15
|
+
exit 5
|
16
|
+
rescue VersionConflict => e
|
17
|
+
Bundler.logger.error e.message
|
18
|
+
exit 6
|
19
|
+
rescue GemNotFound => e
|
20
|
+
Bundler.logger.error e.message
|
21
|
+
exit 7
|
22
|
+
rescue InvalidCacheArgument => e
|
23
|
+
Bundler.logger.error e.message
|
24
|
+
exit 8
|
25
|
+
rescue SourceNotCached => e
|
26
|
+
Bundler.logger.error e.message
|
27
|
+
exit 9
|
28
|
+
rescue ManifestFileNotFound => e
|
29
|
+
Bundler.logger.error e.message
|
30
|
+
exit 10
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(options)
|
34
|
+
@options = options
|
35
|
+
@bundle = Bundle.load(@options[:manifest])
|
36
|
+
end
|
37
|
+
|
38
|
+
def bundle
|
39
|
+
@bundle.install(@options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def cache
|
43
|
+
gemfile = @options[:cache]
|
44
|
+
|
45
|
+
if File.extname(gemfile) == ".gem"
|
46
|
+
if !File.exist?(gemfile)
|
47
|
+
raise InvalidCacheArgument, "'#{gemfile}' does not exist."
|
48
|
+
end
|
49
|
+
@bundle.cache(gemfile)
|
50
|
+
elsif File.directory?(gemfile) || gemfile.include?('/')
|
51
|
+
if !File.directory?(gemfile)
|
52
|
+
raise InvalidCacheArgument, "'#{gemfile}' does not exist."
|
53
|
+
end
|
54
|
+
gemfiles = Dir["#{gemfile}/*.gem"]
|
55
|
+
if gemfiles.empty?
|
56
|
+
raise InvalidCacheArgument, "'#{gemfile}' contains no gemfiles"
|
57
|
+
end
|
58
|
+
@bundle.cache(*gemfiles)
|
59
|
+
else
|
60
|
+
raise InvalidCacheArgument, "w0t? '#{gemfile}' means nothing to me."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def prune
|
65
|
+
@bundle.prune(@options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def list
|
69
|
+
@bundle.list(@options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def list_outdated
|
73
|
+
@bundle.list_outdated(@options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def exec
|
77
|
+
@bundle.setup_environment
|
78
|
+
# w0t?
|
79
|
+
super(*$command)
|
80
|
+
end
|
81
|
+
|
82
|
+
def run(command)
|
83
|
+
send(command)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Bundler
|
2
|
+
class InvalidEnvironmentName < StandardError; end
|
3
|
+
|
4
|
+
class Dependency < Gem::Dependency
|
5
|
+
attr_reader :name, :version, :require_as, :only, :except
|
6
|
+
attr_accessor :source
|
7
|
+
|
8
|
+
def initialize(name, options = {}, &block)
|
9
|
+
options.each do |k, v|
|
10
|
+
options[k.to_s] = v
|
11
|
+
end
|
12
|
+
|
13
|
+
super(name, options["version"] || ">= 0")
|
14
|
+
|
15
|
+
@require_as = options["require_as"]
|
16
|
+
@only = options["only"]
|
17
|
+
@except = options["except"]
|
18
|
+
@source = options["source"]
|
19
|
+
@block = block
|
20
|
+
|
21
|
+
if (@only && @only.include?("rubygems")) || (@except && @except.include?("rubygems"))
|
22
|
+
raise InvalidEnvironmentName, "'rubygems' is not a valid environment name"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def in?(environment)
|
27
|
+
environment = environment.to_s
|
28
|
+
|
29
|
+
return false unless !@only || @only.include?(environment)
|
30
|
+
return false if @except && @except.include?(environment)
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def require_env(environment)
|
35
|
+
return unless in?(environment)
|
36
|
+
|
37
|
+
if @require_as
|
38
|
+
Array(@require_as).each { |file| require file }
|
39
|
+
else
|
40
|
+
begin
|
41
|
+
require name
|
42
|
+
rescue LoadError
|
43
|
+
# Do nothing
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@block.call if @block
|
48
|
+
end
|
49
|
+
|
50
|
+
def no_bundle?
|
51
|
+
source == SystemGemSource.instance
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(o)
|
55
|
+
[name, version, require_as, only, except] ==
|
56
|
+
[o.name, o.version, o.require_as, o.only, o.except]
|
57
|
+
end
|
58
|
+
|
59
|
+
alias version version_requirements
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module Bundler
|
2
|
+
class ManifestFileNotFound < StandardError; end
|
3
|
+
class InvalidKey < StandardError; end
|
4
|
+
class DefaultManifestNotFound < StandardError; end
|
5
|
+
|
6
|
+
class Dsl
|
7
|
+
def self.evaluate(file, bundle, environment)
|
8
|
+
builder = new(bundle, environment)
|
9
|
+
builder.instance_eval(File.read(file.to_s), file.to_s, 1)
|
10
|
+
environment
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(bundle, environment)
|
14
|
+
@bundle = bundle
|
15
|
+
@environment = environment
|
16
|
+
@directory_sources = []
|
17
|
+
@git_sources = {}
|
18
|
+
@only, @except, @directory, @git = nil, nil, nil, nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def bundle_path(path)
|
22
|
+
@bundle.path = Pathname.new(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def bin_path(path)
|
26
|
+
@bundle.bindir = Pathname.new(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_rubygems
|
30
|
+
@environment.rubygems = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def disable_system_gems
|
34
|
+
@environment.system_gems = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def source(source)
|
38
|
+
source = GemSource.new(@bundle, :uri => source)
|
39
|
+
unless @environment.sources.include?(source)
|
40
|
+
@environment.add_source(source)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def only(*env)
|
45
|
+
old, @only = @only, _combine_only(env)
|
46
|
+
yield
|
47
|
+
@only = old
|
48
|
+
end
|
49
|
+
|
50
|
+
def except(*env)
|
51
|
+
old, @except = @except, _combine_except(env)
|
52
|
+
yield
|
53
|
+
@except = old
|
54
|
+
end
|
55
|
+
|
56
|
+
def directory(path, options = {})
|
57
|
+
raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
|
58
|
+
@directory = DirectorySource.new(@bundle, options.merge(:location => path))
|
59
|
+
@directory_sources << @directory
|
60
|
+
@environment.add_priority_source(@directory)
|
61
|
+
retval = yield if block_given?
|
62
|
+
@directory = nil
|
63
|
+
retval
|
64
|
+
end
|
65
|
+
|
66
|
+
def git(uri, options = {})
|
67
|
+
raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
|
68
|
+
@git = GitSource.new(@bundle, options.merge(:uri => uri))
|
69
|
+
@git_sources[uri] = @git
|
70
|
+
@environment.add_priority_source(@git)
|
71
|
+
retval = yield if block_given?
|
72
|
+
@git = nil
|
73
|
+
retval
|
74
|
+
end
|
75
|
+
|
76
|
+
def clear_sources
|
77
|
+
@environment.clear_sources
|
78
|
+
end
|
79
|
+
|
80
|
+
def gem(name, *args)
|
81
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
82
|
+
version = args.last
|
83
|
+
|
84
|
+
keys = :vendored_at, :path, :only, :except, :git, :path, :bundle, :require_as, :tag, :branch, :ref
|
85
|
+
unless (invalid = options.keys - keys).empty?
|
86
|
+
raise InvalidKey, "Only #{keys.join(", ")} are valid options to #gem. You used #{invalid.join(", ")}"
|
87
|
+
end
|
88
|
+
|
89
|
+
if path = options.delete(:vendored_at)
|
90
|
+
options[:path] = path
|
91
|
+
warn "The :vendored_at option is deprecated. Use :path instead.\nFrom #{caller[0]}"
|
92
|
+
end
|
93
|
+
|
94
|
+
options[:only] = _combine_only(options[:only] || options["only"])
|
95
|
+
options[:except] = _combine_except(options[:except] || options["except"])
|
96
|
+
|
97
|
+
dep = Dependency.new(name, options.merge(:version => version))
|
98
|
+
|
99
|
+
if options.key?(:bundle) && !options[:bundle]
|
100
|
+
dep.source = SystemGemSource.new(@bundle)
|
101
|
+
elsif @git || options[:git]
|
102
|
+
dep.source = _handle_git_option(name, version, options)
|
103
|
+
elsif @directory || options[:path]
|
104
|
+
dep.source = _handle_vendored_option(name, version, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
@environment.dependencies << dep
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def _version?(version)
|
113
|
+
version && Gem::Version.new(version) rescue false
|
114
|
+
end
|
115
|
+
|
116
|
+
def _handle_vendored_option(name, version, options)
|
117
|
+
dir, path = _find_directory_source(options[:path])
|
118
|
+
|
119
|
+
if dir
|
120
|
+
dir.required_specs << name
|
121
|
+
dir.add_spec(path, name, version) if _version?(version)
|
122
|
+
dir
|
123
|
+
else
|
124
|
+
directory options[:path] do
|
125
|
+
_handle_vendored_option(name, version, {})
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def _find_directory_source(path)
|
131
|
+
if @directory
|
132
|
+
return @directory, Pathname.new(path || '')
|
133
|
+
end
|
134
|
+
|
135
|
+
path = @bundle.gemfile.dirname.join(path)
|
136
|
+
|
137
|
+
@directory_sources.each do |s|
|
138
|
+
if s.location.expand_path.to_s < path.expand_path.to_s
|
139
|
+
return s, path.relative_path_from(s.location)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
|
146
|
+
def _handle_git_option(name, version, options)
|
147
|
+
git = options[:git].to_s
|
148
|
+
ref = options[:ref] || options[:tag]
|
149
|
+
branch = options[:branch]
|
150
|
+
|
151
|
+
if source = @git || @git_sources[git]
|
152
|
+
if ref && source.ref != ref
|
153
|
+
raise GitSourceError, "'#{git}' already specified with ref: #{source.ref}"
|
154
|
+
elsif branch && source.branch != branch
|
155
|
+
raise GitSourceError, "'#{git}' already specified with branch: #{source.branch}"
|
156
|
+
end
|
157
|
+
|
158
|
+
source.required_specs << name
|
159
|
+
source.add_spec(Pathname.new(options[:path] || '.'), name, version) if _version?(version)
|
160
|
+
source
|
161
|
+
else
|
162
|
+
git(git, :ref => ref, :branch => branch) do
|
163
|
+
_handle_git_option(name, version, options)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def _combine_only(only)
|
169
|
+
return @only unless only
|
170
|
+
only = Array(only).compact.uniq.map { |o| o.to_s }
|
171
|
+
only &= @only if @only
|
172
|
+
only
|
173
|
+
end
|
174
|
+
|
175
|
+
def _combine_except(except)
|
176
|
+
return @except unless except
|
177
|
+
except = Array(except).compact.uniq.map { |o| o.to_s }
|
178
|
+
except |= @except if @except
|
179
|
+
except
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|