bundler 1.0.0.beta.5 → 1.0.0.beta.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- data/TODO.md +2 -10
- data/bin/bundle +2 -1
- data/lib/bundler/cli.rb +59 -16
- data/lib/bundler/definition.rb +12 -7
- data/lib/bundler/dsl.rb +20 -3
- data/lib/bundler/environment.rb +3 -3
- data/lib/bundler/lockfile_parser.rb +5 -4
- data/lib/bundler/rubygems_ext.rb +5 -0
- data/lib/bundler/runtime.rb +34 -16
- data/lib/bundler/settings.rb +38 -16
- data/lib/bundler/source.rb +31 -8
- data/lib/bundler/spec_set.rb +1 -1
- data/lib/bundler/vendor/thor.rb +40 -18
- data/lib/bundler/vendor/thor/base.rb +7 -7
- data/lib/bundler/vendor/thor/invocation.rb +1 -1
- data/lib/bundler/vendor/thor/parser/argument.rb +15 -15
- data/lib/bundler/vendor/thor/parser/option.rb +38 -46
- data/lib/bundler/vendor/thor/parser/options.rb +1 -1
- data/lib/bundler/vendor/thor/shell.rb +7 -2
- data/lib/bundler/vendor/thor/shell/basic.rb +9 -5
- data/lib/bundler/vendor/thor/shell/html.rb +121 -0
- data/lib/bundler/vendor/thor/task.rb +58 -46
- data/lib/bundler/vendor/thor/version.rb +1 -1
- data/lib/bundler/version.rb +2 -2
- metadata +8 -4
data/lib/bundler/settings.rb
CHANGED
@@ -2,24 +2,31 @@ module Bundler
|
|
2
2
|
class Settings
|
3
3
|
def initialize(root)
|
4
4
|
@root = root
|
5
|
-
@
|
5
|
+
@local_config = File.exist?(local_config_file) ? YAML.load_file(local_config_file) : {}
|
6
|
+
@global_config = File.exist?(global_config_file) ? YAML.load_file(global_config_file) : {}
|
6
7
|
end
|
7
8
|
|
8
9
|
def [](key)
|
9
10
|
key = key_for(key)
|
10
|
-
@
|
11
|
+
@local_config[key] || ENV[key] || @global_config[key]
|
11
12
|
end
|
12
13
|
|
13
14
|
def []=(key, value)
|
15
|
+
set_key(key, value, @local_config, local_config_file)
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_global(key, value)
|
19
|
+
set_key(key, value, @global_config, global_config_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def locations(key)
|
14
23
|
key = key_for(key)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
value
|
24
|
+
|
25
|
+
locations = {}
|
26
|
+
locations[:local] = @local_config[key]
|
27
|
+
locations[:env] = ENV[key]
|
28
|
+
locations[:global] = @global_config[key]
|
29
|
+
locations
|
23
30
|
end
|
24
31
|
|
25
32
|
def without=(array)
|
@@ -32,11 +39,10 @@ module Bundler
|
|
32
39
|
self[:without] ? self[:without].split(":").map { |w| w.to_sym } : []
|
33
40
|
end
|
34
41
|
|
35
|
-
# @
|
42
|
+
# @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"]
|
36
43
|
def path
|
37
|
-
path = ENV[key_for(:path)]
|
38
|
-
|
39
|
-
return path if path && !@config.key?(key_for(:path))
|
44
|
+
path = ENV[key_for(:path)] || @global_config[key_for(:path)]
|
45
|
+
return path if path && !@local_config.key?(key_for(:path))
|
40
46
|
|
41
47
|
if path = self[:path]
|
42
48
|
"#{path}/#{Bundler.ruby_scope}"
|
@@ -47,12 +53,28 @@ module Bundler
|
|
47
53
|
|
48
54
|
private
|
49
55
|
|
56
|
+
def set_key(key, value, hash, file)
|
57
|
+
key = key_for(key)
|
58
|
+
|
59
|
+
unless hash[key] == value
|
60
|
+
hash[key] = value
|
61
|
+
FileUtils.mkdir_p(file.dirname)
|
62
|
+
File.open(file, "w") { |f| f.puts hash.to_yaml }
|
63
|
+
end
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
50
67
|
def key_for(key)
|
51
68
|
"BUNDLE_#{key.to_s.upcase}"
|
52
69
|
end
|
53
70
|
|
54
|
-
def
|
71
|
+
def global_config_file
|
72
|
+
file = ENV["BUNDLE_CONFIG"] || File.join(Gem.user_home, ".bundle/config")
|
73
|
+
Pathname.new(file)
|
74
|
+
end
|
75
|
+
|
76
|
+
def local_config_file
|
55
77
|
Pathname.new("#{@root}/.bundle/config")
|
56
78
|
end
|
57
79
|
end
|
58
|
-
end
|
80
|
+
end
|
data/lib/bundler/source.rb
CHANGED
@@ -258,7 +258,7 @@ module Bundler
|
|
258
258
|
class Path
|
259
259
|
attr_reader :path, :options
|
260
260
|
# Kind of a hack, but needed for the lock file parser
|
261
|
-
attr_accessor :version
|
261
|
+
attr_accessor :name, :version
|
262
262
|
|
263
263
|
DEFAULT_GLOB = "{,*/}*.gemspec"
|
264
264
|
|
@@ -523,7 +523,7 @@ module Bundler
|
|
523
523
|
|
524
524
|
# TODO: actually cache git specs
|
525
525
|
def specs
|
526
|
-
if
|
526
|
+
if allow_git_ops? && !@update
|
527
527
|
# Start by making sure the git cache is up to date
|
528
528
|
cache
|
529
529
|
checkout
|
@@ -537,7 +537,7 @@ module Bundler
|
|
537
537
|
|
538
538
|
unless @installed
|
539
539
|
Bundler.ui.debug " * Checking out revision: #{ref}"
|
540
|
-
checkout
|
540
|
+
checkout if allow_git_ops?
|
541
541
|
@installed = true
|
542
542
|
end
|
543
543
|
generate_bin(spec)
|
@@ -553,12 +553,18 @@ module Bundler
|
|
553
553
|
private
|
554
554
|
|
555
555
|
def git(command)
|
556
|
-
|
556
|
+
if allow_git_ops?
|
557
|
+
out = %x{git #{command}}
|
557
558
|
|
558
|
-
|
559
|
-
|
559
|
+
if $? != 0
|
560
|
+
raise GitError, "An error has occurred in git. Cannot complete bundling."
|
561
|
+
end
|
562
|
+
out
|
563
|
+
else
|
564
|
+
raise GitError, "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " \
|
565
|
+
"this error message could probably be more useful. Please submit a ticket at http://github.com/carlhuda/bundler/issues " \
|
566
|
+
"with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
|
560
567
|
end
|
561
|
-
out
|
562
568
|
end
|
563
569
|
|
564
570
|
def base_name
|
@@ -595,6 +601,7 @@ module Bundler
|
|
595
601
|
|
596
602
|
def cache
|
597
603
|
if cached?
|
604
|
+
return if has_revision_cached?
|
598
605
|
Bundler.ui.info "Updating #{uri}"
|
599
606
|
in_cache { git %|fetch --force --quiet "#{uri}" refs/heads/*:refs/heads/*| }
|
600
607
|
else
|
@@ -620,8 +627,24 @@ module Bundler
|
|
620
627
|
end
|
621
628
|
end
|
622
629
|
|
630
|
+
def has_revision_cached?
|
631
|
+
return unless @revision
|
632
|
+
in_cache { git %|cat-file -t #{@revision}| }
|
633
|
+
$? == 0
|
634
|
+
end
|
635
|
+
|
636
|
+
def allow_git_ops?
|
637
|
+
@allow_remote || @allow_cached
|
638
|
+
end
|
639
|
+
|
623
640
|
def revision
|
624
|
-
@revision ||=
|
641
|
+
@revision ||= begin
|
642
|
+
if allow_git_ops?
|
643
|
+
in_cache { git("rev-parse #{ref}").strip }
|
644
|
+
else
|
645
|
+
raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
|
646
|
+
end
|
647
|
+
end
|
625
648
|
end
|
626
649
|
|
627
650
|
def cached?
|
data/lib/bundler/spec_set.rb
CHANGED
data/lib/bundler/vendor/thor.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'thor/base'
|
2
2
|
|
3
|
-
# TODO: Update thor to allow for git-style CLI (git bisect run)
|
4
3
|
class Thor
|
5
4
|
class << self
|
6
5
|
# Sets the default task when thor is executed without an explicit task to be called.
|
@@ -24,6 +23,7 @@ class Thor
|
|
24
23
|
# ==== Parameters
|
25
24
|
# usage<String>
|
26
25
|
# description<String>
|
26
|
+
# options<String>
|
27
27
|
#
|
28
28
|
def desc(usage, description, options={})
|
29
29
|
if options[:for]
|
@@ -31,7 +31,7 @@ class Thor
|
|
31
31
|
task.usage = usage if usage
|
32
32
|
task.description = description if description
|
33
33
|
else
|
34
|
-
@usage, @desc = usage, description
|
34
|
+
@usage, @desc, @hide = usage, description, options[:hide] || false
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -135,6 +135,8 @@ class Thor
|
|
135
135
|
# script.invoke(:task, first_arg, second_arg, third_arg)
|
136
136
|
#
|
137
137
|
def start(original_args=ARGV, config={})
|
138
|
+
@@original_args = original_args
|
139
|
+
|
138
140
|
super do |given_args|
|
139
141
|
meth = given_args.first.to_s
|
140
142
|
|
@@ -154,7 +156,7 @@ class Thor
|
|
154
156
|
args, opts = given_args, {}
|
155
157
|
end
|
156
158
|
|
157
|
-
task ||= Thor::
|
159
|
+
task ||= Thor::DynamicTask.new(meth)
|
158
160
|
trailing = args[Range.new(arguments.size, -1)]
|
159
161
|
new(args, opts, config).invoke(task, trailing || [])
|
160
162
|
end
|
@@ -188,8 +190,8 @@ class Thor
|
|
188
190
|
# ==== Parameters
|
189
191
|
# shell<Thor::Shell>
|
190
192
|
#
|
191
|
-
def help(shell)
|
192
|
-
list = printable_tasks
|
193
|
+
def help(shell, subcommand = false)
|
194
|
+
list = printable_tasks(true, subcommand)
|
193
195
|
Thor::Util.thor_classes_in(self).each do |klass|
|
194
196
|
list += klass.printable_tasks(false)
|
195
197
|
end
|
@@ -202,17 +204,25 @@ class Thor
|
|
202
204
|
end
|
203
205
|
|
204
206
|
# Returns tasks ready to be printed.
|
205
|
-
def printable_tasks(all=true)
|
207
|
+
def printable_tasks(all = true, subcommand = false)
|
206
208
|
(all ? all_tasks : tasks).map do |_, task|
|
209
|
+
next if task.hidden?
|
207
210
|
item = []
|
208
|
-
item << banner(task)
|
211
|
+
item << banner(task, false, subcommand)
|
209
212
|
item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
|
210
213
|
item
|
211
|
-
end
|
214
|
+
end.compact
|
212
215
|
end
|
213
216
|
|
214
|
-
def
|
215
|
-
|
217
|
+
def subcommands
|
218
|
+
@@subcommands ||= {}
|
219
|
+
end
|
220
|
+
|
221
|
+
def subcommand(subcommand, subcommand_class)
|
222
|
+
subcommand = subcommand.to_s
|
223
|
+
subcommands[subcommand] = subcommand_class
|
224
|
+
subcommand_class.subcommand_help subcommand
|
225
|
+
define_method(subcommand) { |*_| subcommand_class.start(subcommand_args) }
|
216
226
|
end
|
217
227
|
|
218
228
|
protected
|
@@ -222,8 +232,8 @@ class Thor
|
|
222
232
|
# the task that is going to be invoked and a boolean which indicates if
|
223
233
|
# the namespace should be displayed as arguments.
|
224
234
|
#
|
225
|
-
def banner(task)
|
226
|
-
"#{
|
235
|
+
def banner(task, namespace = nil, subcommand = false)
|
236
|
+
"#{$0} #{task.formatted_usage(self, $thor_runner, subcommand)}"
|
227
237
|
end
|
228
238
|
|
229
239
|
def baseclass #:nodoc:
|
@@ -232,8 +242,9 @@ class Thor
|
|
232
242
|
|
233
243
|
def create_task(meth) #:nodoc:
|
234
244
|
if @usage && @desc
|
235
|
-
|
236
|
-
|
245
|
+
base_class = @hide ? Thor::HiddenTask : Thor::Task
|
246
|
+
tasks[meth.to_s] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
|
247
|
+
@usage, @desc, @long_desc, @method_options, @hide = nil
|
237
248
|
true
|
238
249
|
elsif self.all_tasks[meth.to_s] || meth.to_sym == :method_missing
|
239
250
|
true
|
@@ -254,10 +265,21 @@ class Thor
|
|
254
265
|
# If a map can't be found use the sent name or the default task.
|
255
266
|
#
|
256
267
|
def normalize_task_name(meth) #:nodoc:
|
257
|
-
|
258
|
-
meth = mapping || meth || default_task
|
268
|
+
meth = map[meth.to_s] || meth || default_task
|
259
269
|
meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
|
260
270
|
end
|
271
|
+
|
272
|
+
def subcommand_help(cmd)
|
273
|
+
desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
|
274
|
+
class_eval <<-RUBY
|
275
|
+
def help(task = nil, subcommand = true); super; end
|
276
|
+
RUBY
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
def subcommand_args
|
282
|
+
@@original_args[1..-1]
|
261
283
|
end
|
262
284
|
|
263
285
|
include Thor::Base
|
@@ -265,7 +287,7 @@ class Thor
|
|
265
287
|
map HELP_MAPPINGS => :help
|
266
288
|
|
267
289
|
desc "help [TASK]", "Describe available tasks or one specific task"
|
268
|
-
def help(task=nil)
|
269
|
-
task ? self.class.task_help(shell, task) : self.class.help(shell)
|
290
|
+
def help(task = nil, subcommand = false)
|
291
|
+
task ? self.class.task_help(shell, task) : self.class.help(shell, subcommand)
|
270
292
|
end
|
271
293
|
end
|
@@ -336,6 +336,7 @@ class Thor
|
|
336
336
|
def no_tasks
|
337
337
|
@no_tasks = true
|
338
338
|
yield
|
339
|
+
ensure
|
339
340
|
@no_tasks = false
|
340
341
|
end
|
341
342
|
|
@@ -382,13 +383,17 @@ class Thor
|
|
382
383
|
end
|
383
384
|
|
384
385
|
def handle_no_task_error(task) #:nodoc:
|
385
|
-
if
|
386
|
+
if $thor_runner
|
386
387
|
raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
|
387
388
|
else
|
388
389
|
raise UndefinedTaskError, "Could not find task #{task.inspect}."
|
389
390
|
end
|
390
391
|
end
|
391
392
|
|
393
|
+
def handle_argument_error(task, error) #:nodoc:
|
394
|
+
raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{self.banner(task).inspect}."
|
395
|
+
end
|
396
|
+
|
392
397
|
protected
|
393
398
|
|
394
399
|
# Prints the class options per group. If an option does not belong to
|
@@ -445,7 +450,7 @@ class Thor
|
|
445
450
|
def build_option(name, options, scope) #:nodoc:
|
446
451
|
scope[name] = Thor::Option.new(name, options[:desc], options[:required],
|
447
452
|
options[:type], options[:default], options[:banner],
|
448
|
-
options[:group], options[:aliases])
|
453
|
+
options[:lazy_default], options[:group], options[:aliases])
|
449
454
|
end
|
450
455
|
|
451
456
|
# Receives a hash of options, parse them and add to the scope. This is a
|
@@ -516,11 +521,6 @@ class Thor
|
|
516
521
|
false
|
517
522
|
end
|
518
523
|
|
519
|
-
# Returns the base for banner.
|
520
|
-
def banner_base
|
521
|
-
@banner_base ||= $thor_runner ? "thor" : File.basename($0.split(" ").first)
|
522
|
-
end
|
523
|
-
|
524
524
|
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
525
525
|
# finishes.
|
526
526
|
def baseclass #:nodoc:
|
@@ -156,7 +156,7 @@ class Thor
|
|
156
156
|
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
157
157
|
|
158
158
|
task ||= klass.default_task if klass.respond_to?(:default_task)
|
159
|
-
task = klass.all_tasks[task.to_s] || Thor::
|
159
|
+
task = klass.all_tasks[task.to_s] || Thor::DynamicTask.new(task) if task && !task.is_a?(Thor::Task)
|
160
160
|
task
|
161
161
|
end
|
162
162
|
|
@@ -31,10 +31,10 @@ class Thor
|
|
31
31
|
|
32
32
|
def show_default?
|
33
33
|
case default
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
when Array, String, Hash
|
35
|
+
!default.empty?
|
36
|
+
else
|
37
|
+
default
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -45,21 +45,21 @@ class Thor
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def valid_type?(type)
|
48
|
-
VALID_TYPES.include?(type.to_sym)
|
48
|
+
self.class::VALID_TYPES.include?(type.to_sym)
|
49
49
|
end
|
50
50
|
|
51
51
|
def default_banner
|
52
52
|
case type
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
when :boolean
|
54
|
+
nil
|
55
|
+
when :string, :default
|
56
|
+
human_name.upcase
|
57
|
+
when :numeric
|
58
|
+
"N"
|
59
|
+
when :hash
|
60
|
+
"key:value"
|
61
|
+
when :array
|
62
|
+
"one two three"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -1,13 +1,14 @@
|
|
1
1
|
class Thor
|
2
2
|
class Option < Argument #:nodoc:
|
3
|
-
attr_reader :aliases, :group
|
3
|
+
attr_reader :aliases, :group, :lazy_default
|
4
4
|
|
5
5
|
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
6
6
|
|
7
|
-
def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil)
|
7
|
+
def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, lazy_default=nil, group=nil, aliases=nil)
|
8
8
|
super(name, description, required, type, default, banner)
|
9
|
-
@
|
10
|
-
@group
|
9
|
+
@lazy_default = lazy_default
|
10
|
+
@group = group.to_s.capitalize if group
|
11
|
+
@aliases = [*aliases].compact
|
11
12
|
end
|
12
13
|
|
13
14
|
# This parse quick options given as method_options. It makes several
|
@@ -48,23 +49,22 @@ class Thor
|
|
48
49
|
default = value
|
49
50
|
|
50
51
|
type = case value
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
value.class.name.downcase.to_sym
|
52
|
+
when Symbol
|
53
|
+
default = nil
|
54
|
+
if VALID_TYPES.include?(value)
|
55
|
+
value
|
56
|
+
elsif required = (value == :required)
|
57
|
+
:string
|
58
|
+
end
|
59
|
+
when TrueClass, FalseClass
|
60
|
+
:boolean
|
61
|
+
when Numeric
|
62
|
+
:numeric
|
63
|
+
when Hash, Array, String
|
64
|
+
value.class.name.downcase.to_sym
|
65
65
|
end
|
66
66
|
|
67
|
-
self.new(name.to_s, nil, required, type, default, nil, nil, aliases)
|
67
|
+
self.new(name.to_s, nil, required, type, default, nil, nil, nil, aliases)
|
68
68
|
end
|
69
69
|
|
70
70
|
def switch_name
|
@@ -91,38 +91,30 @@ class Thor
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
else
|
101
|
-
super
|
102
|
-
end
|
94
|
+
VALID_TYPES.each do |type|
|
95
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
96
|
+
def #{type}?
|
97
|
+
self.type == #{type.inspect}
|
98
|
+
end
|
99
|
+
RUBY
|
103
100
|
end
|
104
101
|
|
105
|
-
|
106
|
-
|
107
|
-
def validate!
|
108
|
-
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
|
109
|
-
end
|
110
|
-
|
111
|
-
def valid_type?(type)
|
112
|
-
VALID_TYPES.include?(type.to_sym)
|
113
|
-
end
|
102
|
+
protected
|
114
103
|
|
115
|
-
|
116
|
-
|
117
|
-
|
104
|
+
def validate!
|
105
|
+
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
|
106
|
+
end
|
118
107
|
|
119
|
-
|
120
|
-
|
121
|
-
|
108
|
+
def dasherized?
|
109
|
+
name.index('-') == 0
|
110
|
+
end
|
122
111
|
|
123
|
-
|
124
|
-
|
125
|
-
|
112
|
+
def undasherize(str)
|
113
|
+
str.sub(/^-{1,2}/, '')
|
114
|
+
end
|
126
115
|
|
116
|
+
def dasherize(str)
|
117
|
+
(str.length > 1 ? "--" : "-") + str.gsub('_', '-')
|
118
|
+
end
|
127
119
|
end
|
128
120
|
end
|