bowline-bundler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|