bundler 1.1.5 → 1.2.0.pre
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.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- data/.travis.yml +10 -7
- data/CHANGELOG.md +27 -8
- data/ISSUES.md +20 -16
- data/README.md +2 -0
- data/Rakefile +6 -5
- data/bin/bundle +5 -3
- data/lib/bundler.rb +33 -13
- data/lib/bundler/capistrano.rb +1 -1
- data/lib/bundler/cli.rb +108 -20
- data/lib/bundler/definition.rb +76 -20
- data/lib/bundler/deployment.rb +4 -4
- data/lib/bundler/dsl.rb +26 -25
- data/lib/bundler/fetcher.rb +4 -13
- data/lib/bundler/gem_helper.rb +17 -5
- data/lib/bundler/graph.rb +10 -10
- data/lib/bundler/installer.rb +34 -2
- data/lib/bundler/ruby_version.rb +94 -0
- data/lib/bundler/runtime.rb +1 -1
- data/lib/bundler/settings.rb +18 -13
- data/lib/bundler/source.rb +316 -150
- data/lib/bundler/templates/newgem/README.md.tt +1 -1
- data/lib/bundler/vendor/thor/parser/options.rb +0 -3
- data/lib/bundler/vendored_thor.rb +1 -2
- data/lib/bundler/version.rb +1 -1
- data/man/bundle-config.ronn +8 -0
- data/man/bundle-install.ronn +6 -0
- data/man/bundle-package.ronn +3 -3
- data/man/gemfile.5.ronn +16 -3
- data/spec/bundler/dsl_spec.rb +23 -26
- data/spec/bundler/gem_helper_spec.rb +31 -0
- data/spec/cache/gems_spec.rb +10 -1
- data/spec/cache/git_spec.rb +114 -2
- data/spec/cache/path_spec.rb +85 -9
- data/spec/install/gems/dependency_api_spec.rb +21 -42
- data/spec/install/git_spec.rb +149 -1
- data/spec/lock/lockfile_spec.rb +1 -1
- data/spec/other/config_spec.rb +120 -22
- data/spec/other/newgem_spec.rb +2 -0
- data/spec/other/platform_spec.rb +881 -0
- data/spec/support/helpers.rb +12 -1
- data/spec/support/platforms.rb +33 -0
- data/spec/support/rubygems_hax/platform.rb +12 -1
- data/spec/update/gems_spec.rb +12 -0
- metadata +9 -8
- data/lib/bundler/vendored_persistent.rb +0 -3
- data/spec/install/deprecated_spec.rb +0 -36
@@ -0,0 +1,94 @@
|
|
1
|
+
module Bundler
|
2
|
+
class RubyVersion
|
3
|
+
attr_reader :version, :engine, :engine_version
|
4
|
+
|
5
|
+
def initialize(version, engine, engine_version)
|
6
|
+
# The parameters to this method must satisfy the
|
7
|
+
# following constraints, which are verified in
|
8
|
+
# the DSL:
|
9
|
+
#
|
10
|
+
# * If an engine is specified, an engine version
|
11
|
+
# must also be specified
|
12
|
+
# * If an engine version is specified, an engine
|
13
|
+
# must also be specified
|
14
|
+
# * If the engine is "ruby", the engine version
|
15
|
+
# must not be specified, or the engine version
|
16
|
+
# specified must match the version.
|
17
|
+
|
18
|
+
@version = version
|
19
|
+
@engine = engine || "ruby"
|
20
|
+
@engine_version = engine_version || version
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
output = "ruby #{version}"
|
25
|
+
output << " (#{engine} #{engine_version})" unless engine == "ruby"
|
26
|
+
|
27
|
+
output
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
version == other.version &&
|
32
|
+
engine == other.engine &&
|
33
|
+
engine_version == other.engine_version
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns a tuple of thsee things:
|
37
|
+
# [diff, this, other]
|
38
|
+
# The priority of attributes are
|
39
|
+
# 1. engine
|
40
|
+
# 2. ruby_version
|
41
|
+
# 3. engine_version
|
42
|
+
def diff(other)
|
43
|
+
if engine != other.engine
|
44
|
+
[ :engine, engine, other.engine ]
|
45
|
+
elsif version != other.version
|
46
|
+
[ :version, version, other.version ]
|
47
|
+
elsif engine_version != other.engine_version
|
48
|
+
[ :engine_version, engine_version, other.engine_version ]
|
49
|
+
else
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# A subclass of RubyVersion that implements version,
|
56
|
+
# engine and engine_version based upon the current
|
57
|
+
# information in the system. It can be used anywhere
|
58
|
+
# a RubyVersion object is expected, and can be
|
59
|
+
# compared with a RubyVersion object.
|
60
|
+
class SystemRubyVersion < RubyVersion
|
61
|
+
def initialize(*)
|
62
|
+
# override the default initialize, because
|
63
|
+
# we will implement version, engine and
|
64
|
+
# engine_version dynamically
|
65
|
+
end
|
66
|
+
|
67
|
+
def version
|
68
|
+
RUBY_VERSION
|
69
|
+
end
|
70
|
+
|
71
|
+
def engine
|
72
|
+
if defined?(RUBY_ENGINE)
|
73
|
+
RUBY_ENGINE
|
74
|
+
else
|
75
|
+
# not defined in ruby 1.8.7
|
76
|
+
"ruby"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def engine_version
|
81
|
+
case engine
|
82
|
+
when "ruby"
|
83
|
+
RUBY_VERSION
|
84
|
+
when "rbx"
|
85
|
+
Rubinius::VERSION
|
86
|
+
when "jruby"
|
87
|
+
JRUBY_VERSION
|
88
|
+
else
|
89
|
+
raise BundlerError, "That RUBY_ENGINE is not recognized"
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/bundler/runtime.rb
CHANGED
@@ -97,7 +97,7 @@ module Bundler
|
|
97
97
|
def cache
|
98
98
|
FileUtils.mkdir_p(cache_path) unless File.exists?(cache_path)
|
99
99
|
|
100
|
-
Bundler.ui.info "Updating
|
100
|
+
Bundler.ui.info "Updating files in vendor/cache"
|
101
101
|
specs.each do |spec|
|
102
102
|
next if spec.name == 'bundler'
|
103
103
|
spec.source.cache(spec) if spec.source.respond_to?(:cache)
|
data/lib/bundler/settings.rb
CHANGED
@@ -2,8 +2,8 @@ module Bundler
|
|
2
2
|
class Settings
|
3
3
|
def initialize(root)
|
4
4
|
@root = root
|
5
|
-
@local_config =
|
6
|
-
@global_config =
|
5
|
+
@local_config = (File.exist?(local_config_file) && yaml = YAML.load_file(local_config_file)) ? yaml : {}
|
6
|
+
@global_config = (File.exist?(global_config_file) && yaml = YAML.load_file(global_config_file)) ? yaml : {}
|
7
7
|
end
|
8
8
|
|
9
9
|
def [](key)
|
@@ -15,6 +15,8 @@ module Bundler
|
|
15
15
|
set_key(key, value, @local_config, local_config_file)
|
16
16
|
end
|
17
17
|
|
18
|
+
alias :set_local :[]=
|
19
|
+
|
18
20
|
def delete(key)
|
19
21
|
@local_config.delete(key_for(key))
|
20
22
|
end
|
@@ -32,9 +34,19 @@ module Bundler
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
37
|
+
def local_overrides
|
38
|
+
repos = {}
|
39
|
+
all.each do |k|
|
40
|
+
if k =~ /^local\./
|
41
|
+
repos[$'] = self[k]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
repos
|
45
|
+
end
|
46
|
+
|
35
47
|
def locations(key)
|
48
|
+
key = key_for(key)
|
36
49
|
locations = {}
|
37
|
-
|
38
50
|
locations[:local] = @local_config[key] if @local_config.key?(key)
|
39
51
|
locations[:env] = ENV[key] if ENV[key]
|
40
52
|
locations[:global] = @global_config[key] if @global_config.key?(key)
|
@@ -71,8 +83,9 @@ module Bundler
|
|
71
83
|
|
72
84
|
# @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"]
|
73
85
|
def path
|
74
|
-
|
75
|
-
|
86
|
+
key = key_for(:path)
|
87
|
+
path = ENV[key] || @global_config[key]
|
88
|
+
return path if path && !@local_config.key?(key)
|
76
89
|
|
77
90
|
if path = self[:path]
|
78
91
|
"#{path}/#{Bundler.ruby_scope}"
|
@@ -111,13 +124,5 @@ module Bundler
|
|
111
124
|
def local_config_file
|
112
125
|
Pathname.new("#{@root}/config")
|
113
126
|
end
|
114
|
-
|
115
|
-
def load_config(config_file)
|
116
|
-
if config_file.exist? && !config_file.size.zero?
|
117
|
-
yaml = YAML.load_file(config_file)
|
118
|
-
end
|
119
|
-
yaml || {}
|
120
|
-
end
|
121
|
-
|
122
127
|
end
|
123
128
|
end
|
data/lib/bundler/source.rb
CHANGED
@@ -4,7 +4,7 @@ require "rubygems/installer"
|
|
4
4
|
require "rubygems/spec_fetcher"
|
5
5
|
require "rubygems/format"
|
6
6
|
require "digest/sha1"
|
7
|
-
require "
|
7
|
+
require "fileutils"
|
8
8
|
|
9
9
|
module Bundler
|
10
10
|
module Source
|
@@ -264,12 +264,37 @@ module Bundler
|
|
264
264
|
Bundler.rubygems.sources = old
|
265
265
|
end
|
266
266
|
end
|
267
|
-
|
268
267
|
end
|
269
268
|
|
269
|
+
|
270
270
|
class Path
|
271
|
-
|
272
|
-
|
271
|
+
class Installer < Bundler::GemInstaller
|
272
|
+
def initialize(spec, options = {})
|
273
|
+
@spec = spec
|
274
|
+
@bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
|
275
|
+
@gem_dir = Bundler.rubygems.path(spec.full_gem_path)
|
276
|
+
@wrappers = options[:wrappers] || true
|
277
|
+
@env_shebang = options[:env_shebang] || true
|
278
|
+
@format_executable = options[:format_executable] || false
|
279
|
+
end
|
280
|
+
|
281
|
+
def generate_bin
|
282
|
+
return if spec.executables.nil? || spec.executables.empty?
|
283
|
+
|
284
|
+
if Bundler.requires_sudo?
|
285
|
+
FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
|
286
|
+
end
|
287
|
+
super
|
288
|
+
if Bundler.requires_sudo?
|
289
|
+
Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
|
290
|
+
spec.executables.each do |exe|
|
291
|
+
Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
attr_reader :path, :options
|
273
298
|
attr_writer :name
|
274
299
|
attr_accessor :version
|
275
300
|
|
@@ -287,8 +312,12 @@ module Bundler
|
|
287
312
|
@path = @path.expand_path(Bundler.root) unless @path.relative?
|
288
313
|
end
|
289
314
|
|
290
|
-
@name
|
315
|
+
@name = options["name"]
|
291
316
|
@version = options["version"]
|
317
|
+
|
318
|
+
# Stores the original path. If at any point we move to the
|
319
|
+
# cached directory, we still have the original path to copy from.
|
320
|
+
@original_path = @path
|
292
321
|
end
|
293
322
|
|
294
323
|
def remote!
|
@@ -330,9 +359,46 @@ module Bundler
|
|
330
359
|
File.basename(path.expand_path(Bundler.root).to_s)
|
331
360
|
end
|
332
361
|
|
362
|
+
def install(spec)
|
363
|
+
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
|
364
|
+
# Let's be honest, when we're working from a path, we can't
|
365
|
+
# really expect native extensions to work because the whole point
|
366
|
+
# is to just be able to modify what's in that path and go. So, let's
|
367
|
+
# not put ourselves through the pain of actually trying to generate
|
368
|
+
# the full gem.
|
369
|
+
Installer.new(spec).generate_bin
|
370
|
+
end
|
371
|
+
|
372
|
+
def cache(spec)
|
373
|
+
return unless Bundler.settings[:cache_all]
|
374
|
+
return if @original_path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
|
375
|
+
FileUtils.rm_rf(app_cache_path)
|
376
|
+
FileUtils.cp_r("#{@original_path}/.", app_cache_path)
|
377
|
+
end
|
378
|
+
|
379
|
+
def local_specs(*)
|
380
|
+
@local_specs ||= load_spec_files
|
381
|
+
end
|
382
|
+
|
383
|
+
def specs
|
384
|
+
if has_app_cache?
|
385
|
+
@path = app_cache_path
|
386
|
+
end
|
387
|
+
local_specs
|
388
|
+
end
|
389
|
+
|
390
|
+
private
|
391
|
+
|
392
|
+
def app_cache_path
|
393
|
+
@app_cache_path ||= Bundler.app_cache.join(name)
|
394
|
+
end
|
395
|
+
|
396
|
+
def has_app_cache?
|
397
|
+
SharedHelpers.in_bundle? && app_cache_path.exist?
|
398
|
+
end
|
399
|
+
|
333
400
|
def load_spec_files
|
334
401
|
index = Index.new
|
335
|
-
|
336
402
|
expanded_path = path.expand_path(Bundler.root)
|
337
403
|
|
338
404
|
if File.directory?(expanded_path)
|
@@ -368,61 +434,10 @@ module Bundler
|
|
368
434
|
index
|
369
435
|
end
|
370
436
|
|
371
|
-
def local_specs(*)
|
372
|
-
@local_specs ||= load_spec_files
|
373
|
-
end
|
374
|
-
|
375
|
-
class Installer < Bundler::GemInstaller
|
376
|
-
def initialize(spec, options = {})
|
377
|
-
@spec = spec
|
378
|
-
@bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
|
379
|
-
@gem_dir = Bundler.rubygems.path(spec.full_gem_path)
|
380
|
-
@wrappers = options[:wrappers] || true
|
381
|
-
@env_shebang = options[:env_shebang] || true
|
382
|
-
@format_executable = options[:format_executable] || false
|
383
|
-
end
|
384
|
-
|
385
|
-
def generate_bin
|
386
|
-
return if spec.executables.nil? || spec.executables.empty?
|
387
|
-
|
388
|
-
if Bundler.requires_sudo?
|
389
|
-
FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
|
390
|
-
end
|
391
|
-
super
|
392
|
-
if Bundler.requires_sudo?
|
393
|
-
Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
|
394
|
-
spec.executables.each do |exe|
|
395
|
-
Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
|
396
|
-
end
|
397
|
-
end
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
def install(spec)
|
402
|
-
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
|
403
|
-
# Let's be honest, when we're working from a path, we can't
|
404
|
-
# really expect native extensions to work because the whole point
|
405
|
-
# is to just be able to modify what's in that path and go. So, let's
|
406
|
-
# not put ourselves through the pain of actually trying to generate
|
407
|
-
# the full gem.
|
408
|
-
Installer.new(spec).generate_bin
|
409
|
-
end
|
410
|
-
|
411
|
-
alias specs local_specs
|
412
|
-
|
413
|
-
def cache(spec)
|
414
|
-
unless path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
|
415
|
-
Bundler.ui.warn " * #{spec.name} at `#{path}` will not be cached."
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
private
|
420
|
-
|
421
437
|
def relative_path
|
422
438
|
if path.to_s.match(%r{^#{Regexp.escape Bundler.root.to_s}})
|
423
439
|
return path.relative_path_from(Bundler.root)
|
424
440
|
end
|
425
|
-
|
426
441
|
path
|
427
442
|
end
|
428
443
|
|
@@ -442,7 +457,7 @@ module Bundler
|
|
442
457
|
|
443
458
|
gem_file = Dir.chdir(gem_dir){ Gem::Builder.new(spec).build }
|
444
459
|
|
445
|
-
installer = Installer.new(spec, :env_shebang => false)
|
460
|
+
installer = Path::Installer.new(spec, :env_shebang => false)
|
446
461
|
run_hooks(:pre_install, installer)
|
447
462
|
installer.build_extensions
|
448
463
|
run_hooks(:post_build, installer)
|
@@ -479,20 +494,162 @@ module Bundler
|
|
479
494
|
end
|
480
495
|
|
481
496
|
class Git < Path
|
497
|
+
# The GitProxy is responsible to iteract with git repositories.
|
498
|
+
# All actions required by the Git source is encapsualted in this
|
499
|
+
# object.
|
500
|
+
class GitProxy
|
501
|
+
attr_accessor :path, :uri, :ref, :revision
|
502
|
+
|
503
|
+
def initialize(path, uri, ref, revision=nil, &allow)
|
504
|
+
@path = path
|
505
|
+
@uri = uri
|
506
|
+
@ref = ref
|
507
|
+
@revision = revision
|
508
|
+
@allow = allow || Proc.new { true }
|
509
|
+
end
|
510
|
+
|
511
|
+
def revision
|
512
|
+
@revision ||= allowed_in_path { git("rev-parse #{ref}").strip }
|
513
|
+
end
|
514
|
+
|
515
|
+
def branch
|
516
|
+
@branch ||= allowed_in_path do
|
517
|
+
git("branch") =~ /^\* (.*)$/ && $1.strip
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def contains?(commit)
|
522
|
+
allowed_in_path do
|
523
|
+
result = git_null("branch --contains #{commit}")
|
524
|
+
$? == 0 && result =~ /^\* (.*)$/
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
def checkout
|
529
|
+
if path.exist?
|
530
|
+
return if has_revision_cached?
|
531
|
+
Bundler.ui.info "Updating #{uri}"
|
532
|
+
in_path do
|
533
|
+
git %|fetch --force --quiet --tags #{uri_escaped} "refs/heads/*:refs/heads/*"|
|
534
|
+
end
|
535
|
+
else
|
536
|
+
Bundler.ui.info "Fetching #{uri}"
|
537
|
+
FileUtils.mkdir_p(path.dirname)
|
538
|
+
git %|clone #{uri_escaped} "#{path}" --bare --no-hardlinks|
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
def copy_to(destination, submodules=false)
|
543
|
+
unless File.exist?(destination.join(".git"))
|
544
|
+
FileUtils.mkdir_p(destination.dirname)
|
545
|
+
FileUtils.rm_rf(destination)
|
546
|
+
git %|clone --no-checkout "#{path}" "#{destination}"|
|
547
|
+
File.chmod((0777 & ~File.umask), destination)
|
548
|
+
end
|
549
|
+
|
550
|
+
Dir.chdir(destination) do
|
551
|
+
git %|fetch --force --quiet --tags "#{path}"|
|
552
|
+
git "reset --hard #{@revision}"
|
553
|
+
|
554
|
+
if submodules
|
555
|
+
git "submodule init"
|
556
|
+
git "submodule update"
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
private
|
562
|
+
|
563
|
+
# TODO: Do not rely on /dev/null.
|
564
|
+
# Given that open3 is not cross platform until Ruby 1.9.3,
|
565
|
+
# the best solution is to pipe to /dev/null if it exists.
|
566
|
+
# If it doesn't, everything will work fine, but the user
|
567
|
+
# will get the $stderr messages as well.
|
568
|
+
def git_null(command)
|
569
|
+
if !Bundler::WINDOWS && File.exist?("/dev/null")
|
570
|
+
git("#{command} 2>/dev/null", false)
|
571
|
+
else
|
572
|
+
git(command, false)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
def git(command, check_errors=true)
|
577
|
+
if allow?
|
578
|
+
out = %x{git #{command}}
|
579
|
+
|
580
|
+
if check_errors && $?.exitstatus != 0
|
581
|
+
msg = "Git error: command `git #{command}` in directory #{Dir.pwd} has failed."
|
582
|
+
msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist?
|
583
|
+
raise GitError, msg
|
584
|
+
end
|
585
|
+
out
|
586
|
+
else
|
587
|
+
raise GitError, "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " \
|
588
|
+
"this error message could probably be more useful. Please submit a ticket at http://github.com/carlhuda/bundler/issues " \
|
589
|
+
"with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
def has_revision_cached?
|
594
|
+
return unless @revision
|
595
|
+
in_path { git("cat-file -e #{@revision}") }
|
596
|
+
true
|
597
|
+
rescue GitError
|
598
|
+
false
|
599
|
+
end
|
600
|
+
|
601
|
+
# Escape the URI for git commands
|
602
|
+
def uri_escaped
|
603
|
+
if Bundler::WINDOWS
|
604
|
+
# Windows quoting requires double quotes only, with double quotes
|
605
|
+
# inside the string escaped by being doubled.
|
606
|
+
'"' + uri.gsub('"') {|s| '""'} + '"'
|
607
|
+
else
|
608
|
+
# Bash requires single quoted strings, with the single quotes escaped
|
609
|
+
# by ending the string, escaping the quote, and restarting the string.
|
610
|
+
"'" + uri.gsub("'") {|s| "'\\''"} + "'"
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def allow?
|
615
|
+
@allow.call
|
616
|
+
end
|
617
|
+
|
618
|
+
def in_path(&blk)
|
619
|
+
checkout unless path.exist?
|
620
|
+
Dir.chdir(path, &blk)
|
621
|
+
end
|
622
|
+
|
623
|
+
def allowed_in_path
|
624
|
+
if allow?
|
625
|
+
in_path { yield }
|
626
|
+
else
|
627
|
+
raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
482
632
|
attr_reader :uri, :ref, :options, :submodules
|
483
633
|
|
484
634
|
def initialize(options)
|
485
|
-
|
635
|
+
@options = options
|
636
|
+
@glob = options["glob"] || DEFAULT_GLOB
|
637
|
+
|
638
|
+
@allow_cached = false
|
639
|
+
@allow_remote = false
|
486
640
|
|
487
|
-
#
|
641
|
+
# Stringify options that could be set as symbols
|
488
642
|
%w(ref branch tag revision).each{|k| options[k] = options[k].to_s if options[k] }
|
489
643
|
|
490
644
|
@uri = options["uri"]
|
491
645
|
@ref = options["ref"] || options["branch"] || options["tag"] || 'master'
|
492
|
-
@revision = options["revision"]
|
493
646
|
@submodules = options["submodules"]
|
647
|
+
@name = options["name"]
|
648
|
+
@version = options["version"]
|
649
|
+
|
494
650
|
@update = false
|
495
651
|
@installed = nil
|
652
|
+
@local = false
|
496
653
|
end
|
497
654
|
|
498
655
|
def self.from_lock(options)
|
@@ -522,15 +679,21 @@ module Bundler
|
|
522
679
|
alias == eql?
|
523
680
|
|
524
681
|
def to_s
|
525
|
-
|
526
|
-
|
682
|
+
at = if local?
|
683
|
+
path
|
684
|
+
elsif options["ref"]
|
685
|
+
shortref_for_display(options["ref"])
|
686
|
+
else
|
687
|
+
ref
|
688
|
+
end
|
689
|
+
"#{uri} (at #{at})"
|
527
690
|
end
|
528
691
|
|
529
692
|
def name
|
530
693
|
File.basename(@uri, '.git')
|
531
694
|
end
|
532
695
|
|
533
|
-
def
|
696
|
+
def install_path
|
534
697
|
@install_path ||= begin
|
535
698
|
git_scope = "#{base_name}-#{shortref_for_path(revision)}"
|
536
699
|
|
@@ -542,32 +705,86 @@ module Bundler
|
|
542
705
|
end
|
543
706
|
end
|
544
707
|
|
708
|
+
alias :path :install_path
|
709
|
+
|
545
710
|
def unlock!
|
546
|
-
|
711
|
+
git_proxy.revision = nil
|
712
|
+
end
|
713
|
+
|
714
|
+
def local_override!(path)
|
715
|
+
return false if local?
|
716
|
+
|
717
|
+
path = Pathname.new(path)
|
718
|
+
path = path.expand_path(Bundler.root) unless path.relative?
|
719
|
+
|
720
|
+
unless options["branch"]
|
721
|
+
raise GitError, "Cannot use local override for #{name} at #{path} because " \
|
722
|
+
":branch is not specified in Gemfile. Specify a branch or check " \
|
723
|
+
"`bundle config --delete` to remove the local override"
|
724
|
+
end
|
725
|
+
|
726
|
+
unless path.exist?
|
727
|
+
raise GitError, "Cannot use local override for #{name} because #{path} " \
|
728
|
+
"does not exist. Check `bundle config --delete` to remove the local override"
|
729
|
+
end
|
730
|
+
|
731
|
+
set_local!(path)
|
732
|
+
|
733
|
+
# Create a new git proxy without the cached revision
|
734
|
+
# so the Gemfile.lock always picks up the new revision.
|
735
|
+
@git_proxy = GitProxy.new(path, uri, ref)
|
736
|
+
|
737
|
+
if git_proxy.branch != options["branch"]
|
738
|
+
raise GitError, "Local override for #{name} at #{path} is using branch " \
|
739
|
+
"#{git_proxy.branch} but Gemfile specifies #{options["branch"]}"
|
740
|
+
end
|
741
|
+
|
742
|
+
changed = cached_revision && cached_revision != git_proxy.revision
|
743
|
+
|
744
|
+
if changed && !git_proxy.contains?(cached_revision)
|
745
|
+
raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \
|
746
|
+
"but the current branch in your local override for #{name} does not contain such commit. " \
|
747
|
+
"Please make sure your branch is up to date."
|
748
|
+
end
|
749
|
+
|
750
|
+
changed
|
547
751
|
end
|
548
752
|
|
549
753
|
# TODO: actually cache git specs
|
550
754
|
def specs(*)
|
551
|
-
if
|
552
|
-
|
553
|
-
|
554
|
-
|
755
|
+
if has_app_cache? && !local?
|
756
|
+
set_local!(app_cache_path)
|
757
|
+
end
|
758
|
+
|
759
|
+
if requires_checkout? && !@update
|
760
|
+
git_proxy.checkout
|
761
|
+
git_proxy.copy_to(install_path, submodules)
|
555
762
|
@update = true
|
556
763
|
end
|
764
|
+
|
557
765
|
local_specs
|
558
766
|
end
|
559
767
|
|
560
768
|
def install(spec)
|
561
769
|
Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
|
562
|
-
|
563
|
-
unless @installed
|
770
|
+
if requires_checkout? && !@installed
|
564
771
|
Bundler.ui.debug " * Checking out revision: #{ref}"
|
565
|
-
|
772
|
+
git_proxy.copy_to(install_path, submodules)
|
566
773
|
@installed = true
|
567
774
|
end
|
568
775
|
generate_bin(spec)
|
569
776
|
end
|
570
777
|
|
778
|
+
def cache(spec)
|
779
|
+
return unless Bundler.settings[:cache_all]
|
780
|
+
return if path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
|
781
|
+
cached!
|
782
|
+
FileUtils.rm_rf(app_cache_path)
|
783
|
+
git_proxy.checkout if requires_checkout?
|
784
|
+
git_proxy.copy_to(app_cache_path, @submodules)
|
785
|
+
FileUtils.rm_rf(app_cache_path.join(".git"))
|
786
|
+
end
|
787
|
+
|
571
788
|
def load_spec_files
|
572
789
|
super
|
573
790
|
rescue PathError, GitError
|
@@ -585,23 +802,29 @@ module Bundler
|
|
585
802
|
end
|
586
803
|
end
|
587
804
|
end
|
805
|
+
|
588
806
|
private
|
589
807
|
|
590
|
-
def
|
591
|
-
|
592
|
-
|
808
|
+
def set_local!(path)
|
809
|
+
@local = true
|
810
|
+
@local_specs = @git_proxy = nil
|
811
|
+
@cache_path = @install_path = path
|
812
|
+
end
|
813
|
+
|
814
|
+
def has_app_cache?
|
815
|
+
cached_revision && super
|
816
|
+
end
|
593
817
|
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
end
|
818
|
+
def app_cache_path
|
819
|
+
@app_cache_path ||= Bundler.app_cache.join("#{base_name}-#{shortref_for_path(cached_revision || revision)}")
|
820
|
+
end
|
821
|
+
|
822
|
+
def local?
|
823
|
+
@local
|
824
|
+
end
|
825
|
+
|
826
|
+
def requires_checkout?
|
827
|
+
allow_git_ops? && !local?
|
605
828
|
end
|
606
829
|
|
607
830
|
def base_name
|
@@ -628,82 +851,25 @@ module Bundler
|
|
628
851
|
Digest::SHA1.hexdigest(input)
|
629
852
|
end
|
630
853
|
|
631
|
-
# Escape the URI for git commands
|
632
|
-
def uri_escaped
|
633
|
-
if Bundler::WINDOWS
|
634
|
-
# Windows quoting requires double quotes only, with double quotes
|
635
|
-
# inside the string escaped by being doubled.
|
636
|
-
'"' + uri.gsub('"') {|s| '""'} + '"'
|
637
|
-
else
|
638
|
-
# Bash requires single quoted strings, with the single quotes escaped
|
639
|
-
# by ending the string, escaping the quote, and restarting the string.
|
640
|
-
"'" + uri.gsub("'") {|s| "'\\''"} + "'"
|
641
|
-
end
|
642
|
-
end
|
643
|
-
|
644
|
-
def cache
|
645
|
-
if cached?
|
646
|
-
return if has_revision_cached?
|
647
|
-
Bundler.ui.info "Updating #{uri}"
|
648
|
-
in_cache do
|
649
|
-
git %|fetch --force --quiet --tags #{uri_escaped} "refs/heads/*:refs/heads/*"|
|
650
|
-
end
|
651
|
-
else
|
652
|
-
Bundler.ui.info "Fetching #{uri}"
|
653
|
-
FileUtils.mkdir_p(cache_path.dirname)
|
654
|
-
git %|clone #{uri_escaped} "#{cache_path}" --bare --no-hardlinks|
|
655
|
-
end
|
656
|
-
end
|
657
|
-
|
658
|
-
def checkout
|
659
|
-
unless File.exist?(path.join(".git"))
|
660
|
-
FileUtils.mkdir_p(path.dirname)
|
661
|
-
FileUtils.rm_rf(path)
|
662
|
-
git %|clone --no-checkout "#{cache_path}" "#{path}"|
|
663
|
-
File.chmod((0777 & ~File.umask), path)
|
664
|
-
end
|
665
|
-
Dir.chdir(path) do
|
666
|
-
git %|fetch --force --quiet --tags "#{cache_path}"|
|
667
|
-
git "reset --hard #{revision}"
|
668
|
-
|
669
|
-
if @submodules
|
670
|
-
git "submodule init"
|
671
|
-
git "submodule update"
|
672
|
-
end
|
673
|
-
end
|
674
|
-
end
|
675
|
-
|
676
|
-
def has_revision_cached?
|
677
|
-
return unless @revision
|
678
|
-
in_cache { git %|cat-file -e #{@revision}| }
|
679
|
-
true
|
680
|
-
rescue GitError
|
681
|
-
false
|
682
|
-
end
|
683
|
-
|
684
854
|
def allow_git_ops?
|
685
855
|
@allow_remote || @allow_cached
|
686
856
|
end
|
687
857
|
|
858
|
+
def cached_revision
|
859
|
+
options["revision"]
|
860
|
+
end
|
861
|
+
|
688
862
|
def revision
|
689
|
-
|
690
|
-
if allow_git_ops?
|
691
|
-
in_cache { git("rev-parse #{ref}").strip }
|
692
|
-
else
|
693
|
-
raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
|
694
|
-
end
|
695
|
-
end
|
863
|
+
git_proxy.revision
|
696
864
|
end
|
697
865
|
|
698
866
|
def cached?
|
699
867
|
cache_path.exist?
|
700
868
|
end
|
701
869
|
|
702
|
-
def
|
703
|
-
|
704
|
-
Dir.chdir(cache_path, &blk)
|
870
|
+
def git_proxy
|
871
|
+
@git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision){ allow_git_ops? }
|
705
872
|
end
|
706
873
|
end
|
707
|
-
|
708
874
|
end
|
709
875
|
end
|