bundler 0.8.1 → 0.9.0.pre1
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/README +7 -0
- data/bin/bundle +3 -0
- data/lib/bundler.rb +72 -37
- data/lib/bundler/cli.rb +64 -68
- data/lib/bundler/definition.rb +78 -0
- data/lib/bundler/dependency.rb +7 -57
- data/lib/bundler/dsl.rb +42 -142
- data/lib/bundler/environment.rb +94 -54
- data/lib/bundler/index.rb +98 -0
- data/lib/bundler/installer.rb +137 -0
- data/lib/bundler/remote_specification.rb +1 -1
- data/lib/bundler/resolver.rb +20 -50
- data/lib/bundler/rubygems.rb +22 -0
- data/lib/bundler/source.rb +185 -295
- data/lib/bundler/specification.rb +22 -0
- data/lib/bundler/templates/Gemfile +4 -0
- data/lib/bundler/templates/environment.erb +3 -153
- data/lib/bundler/ui.rb +51 -0
- data/lib/bundler/vendor/thor.rb +241 -0
- data/lib/bundler/vendor/thor/actions.rb +274 -0
- data/lib/bundler/vendor/thor/actions/create_file.rb +103 -0
- data/lib/bundler/vendor/thor/actions/directory.rb +91 -0
- data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
- data/lib/bundler/vendor/thor/actions/file_manipulation.rb +223 -0
- data/lib/bundler/vendor/thor/actions/inject_into_file.rb +101 -0
- data/lib/bundler/vendor/thor/base.rb +515 -0
- data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/bundler/vendor/thor/error.rb +27 -0
- data/lib/bundler/vendor/thor/group.rb +267 -0
- data/lib/bundler/vendor/thor/invocation.rb +178 -0
- data/lib/bundler/vendor/thor/parser.rb +4 -0
- data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
- data/lib/bundler/vendor/thor/parser/arguments.rb +145 -0
- data/lib/bundler/vendor/thor/parser/option.rb +132 -0
- data/lib/bundler/vendor/thor/parser/options.rb +142 -0
- data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
- data/lib/bundler/vendor/thor/runner.rb +303 -0
- data/lib/bundler/vendor/thor/shell.rb +78 -0
- data/lib/bundler/vendor/thor/shell/basic.rb +239 -0
- data/lib/bundler/vendor/thor/shell/color.rb +108 -0
- data/lib/bundler/vendor/thor/task.rb +111 -0
- data/lib/bundler/vendor/thor/util.rb +233 -0
- data/lib/bundler/vendor/thor/version.rb +3 -0
- metadata +48 -26
- data/README.markdown +0 -284
- data/Rakefile +0 -81
- data/lib/bundler/bundle.rb +0 -314
- data/lib/bundler/commands/bundle_command.rb +0 -72
- data/lib/bundler/commands/exec_command.rb +0 -36
- data/lib/bundler/finder.rb +0 -51
- data/lib/bundler/gem_bundle.rb +0 -11
- data/lib/bundler/gem_ext.rb +0 -34
- data/lib/bundler/runtime.rb +0 -2
- data/lib/bundler/templates/app_script.erb +0 -3
- data/lib/bundler/templates/environment_picker.erb +0 -4
- data/lib/rubygems_plugin.rb +0 -6
@@ -0,0 +1,75 @@
|
|
1
|
+
class Thor
|
2
|
+
module CoreExt #:nodoc:
|
3
|
+
|
4
|
+
# A hash with indifferent access and magic predicates.
|
5
|
+
#
|
6
|
+
# hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
|
7
|
+
#
|
8
|
+
# hash[:foo] #=> 'bar'
|
9
|
+
# hash['foo'] #=> 'bar'
|
10
|
+
# hash.foo? #=> true
|
11
|
+
#
|
12
|
+
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
13
|
+
|
14
|
+
def initialize(hash={})
|
15
|
+
super()
|
16
|
+
hash.each do |key, value|
|
17
|
+
self[convert_key(key)] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](key)
|
22
|
+
super(convert_key(key))
|
23
|
+
end
|
24
|
+
|
25
|
+
def []=(key, value)
|
26
|
+
super(convert_key(key), value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(key)
|
30
|
+
super(convert_key(key))
|
31
|
+
end
|
32
|
+
|
33
|
+
def values_at(*indices)
|
34
|
+
indices.collect { |key| self[convert_key(key)] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def merge(other)
|
38
|
+
dup.merge!(other)
|
39
|
+
end
|
40
|
+
|
41
|
+
def merge!(other)
|
42
|
+
other.each do |key, value|
|
43
|
+
self[convert_key(key)] = value
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def convert_key(key)
|
51
|
+
key.is_a?(Symbol) ? key.to_s : key
|
52
|
+
end
|
53
|
+
|
54
|
+
# Magic predicates. For instance:
|
55
|
+
#
|
56
|
+
# options.force? # => !!options['force']
|
57
|
+
# options.shebang # => "/usr/lib/local/ruby"
|
58
|
+
# options.test_framework?(:rspec) # => options[:test_framework] == :rspec
|
59
|
+
#
|
60
|
+
def method_missing(method, *args, &block)
|
61
|
+
method = method.to_s
|
62
|
+
if method =~ /^(\w+)\?$/
|
63
|
+
if args.empty?
|
64
|
+
!!self[$1]
|
65
|
+
else
|
66
|
+
self[$1] == args.first
|
67
|
+
end
|
68
|
+
else
|
69
|
+
self[method]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Thor
|
2
|
+
module CoreExt #:nodoc:
|
3
|
+
|
4
|
+
if RUBY_VERSION >= '1.9'
|
5
|
+
class OrderedHash < ::Hash
|
6
|
+
end
|
7
|
+
else
|
8
|
+
# This class is based on the Ruby 1.9 ordered hashes.
|
9
|
+
#
|
10
|
+
# It keeps the semantics and most of the efficiency of normal hashes
|
11
|
+
# while also keeping track of the order in which elements were set.
|
12
|
+
#
|
13
|
+
class OrderedHash #:nodoc:
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
Node = Struct.new(:key, :value, :next, :prev)
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@hash = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
@hash[key] && @hash[key].value
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
if node = @hash[key]
|
28
|
+
node.value = value
|
29
|
+
else
|
30
|
+
node = Node.new(key, value)
|
31
|
+
|
32
|
+
if @first.nil?
|
33
|
+
@first = @last = node
|
34
|
+
else
|
35
|
+
node.prev = @last
|
36
|
+
@last.next = node
|
37
|
+
@last = node
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@hash[key] = node
|
42
|
+
value
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(key)
|
46
|
+
if node = @hash[key]
|
47
|
+
prev_node = node.prev
|
48
|
+
next_node = node.next
|
49
|
+
|
50
|
+
next_node.prev = prev_node if next_node
|
51
|
+
prev_node.next = next_node if prev_node
|
52
|
+
|
53
|
+
@first = next_node if @first == node
|
54
|
+
@last = prev_node if @last == node
|
55
|
+
|
56
|
+
value = node.value
|
57
|
+
end
|
58
|
+
|
59
|
+
@hash.delete(key)
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def keys
|
64
|
+
self.map { |k, v| k }
|
65
|
+
end
|
66
|
+
|
67
|
+
def values
|
68
|
+
self.map { |k, v| v }
|
69
|
+
end
|
70
|
+
|
71
|
+
def each
|
72
|
+
return unless @first
|
73
|
+
yield [@first.key, @first.value]
|
74
|
+
node = @first
|
75
|
+
yield [node.key, node.value] while node = node.next
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge(other)
|
80
|
+
hash = self.class.new
|
81
|
+
|
82
|
+
self.each do |key, value|
|
83
|
+
hash[key] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
other.each do |key, value|
|
87
|
+
hash[key] = value
|
88
|
+
end
|
89
|
+
|
90
|
+
hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def empty?
|
94
|
+
@hash.empty?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Thor
|
2
|
+
# Thor::Error is raised when it's caused by wrong usage of thor classes. Those
|
3
|
+
# errors have their backtrace supressed and are nicely shown to the user.
|
4
|
+
#
|
5
|
+
# Errors that are caused by the developer, like declaring a method which
|
6
|
+
# overwrites a thor keyword, it SHOULD NOT raise a Thor::Error. This way, we
|
7
|
+
# ensure that developer errors are shown with full backtrace.
|
8
|
+
#
|
9
|
+
class Error < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
# Raised when a task was not found.
|
13
|
+
#
|
14
|
+
class UndefinedTaskError < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised when a task was found, but not invoked properly.
|
18
|
+
#
|
19
|
+
class InvocationError < Error
|
20
|
+
end
|
21
|
+
|
22
|
+
class RequiredArgumentMissingError < InvocationError
|
23
|
+
end
|
24
|
+
|
25
|
+
class MalformattedArgumentError < InvocationError
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# Thor has a special class called Thor::Group. The main difference to Thor class
|
2
|
+
# is that it invokes all tasks at once. It also include some methods that allows
|
3
|
+
# invocations to be done at the class method, which are not available to Thor
|
4
|
+
# tasks.
|
5
|
+
#
|
6
|
+
class Thor::Group
|
7
|
+
class << self
|
8
|
+
# The descrition for this Thor::Group. If none is provided, but a source root
|
9
|
+
# exists, tries to find the USAGE one folder above it, otherwise searches
|
10
|
+
# in the superclass.
|
11
|
+
#
|
12
|
+
# ==== Parameters
|
13
|
+
# description<String>:: The description for this Thor::Group.
|
14
|
+
#
|
15
|
+
def desc(description=nil)
|
16
|
+
case description
|
17
|
+
when nil
|
18
|
+
@desc ||= from_superclass(:desc, nil)
|
19
|
+
else
|
20
|
+
@desc = description
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Start works differently in Thor::Group, it simply invokes all tasks
|
25
|
+
# inside the class.
|
26
|
+
#
|
27
|
+
def start(given_args=ARGV, config={})
|
28
|
+
super do
|
29
|
+
if Thor::HELP_MAPPINGS.include?(given_args.first)
|
30
|
+
help(config[:shell])
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
args, opts = Thor::Options.split(given_args)
|
35
|
+
new(args, opts, config).invoke
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Prints help information.
|
40
|
+
#
|
41
|
+
# ==== Options
|
42
|
+
# short:: When true, shows only usage.
|
43
|
+
#
|
44
|
+
def help(shell)
|
45
|
+
shell.say "Usage:"
|
46
|
+
shell.say " #{banner}\n"
|
47
|
+
shell.say
|
48
|
+
class_options_help(shell)
|
49
|
+
shell.say self.desc if self.desc
|
50
|
+
end
|
51
|
+
|
52
|
+
# Stores invocations for this class merging with superclass values.
|
53
|
+
#
|
54
|
+
def invocations #:nodoc:
|
55
|
+
@invocations ||= from_superclass(:invocations, {})
|
56
|
+
end
|
57
|
+
|
58
|
+
# Stores invocation blocks used on invoke_from_option.
|
59
|
+
#
|
60
|
+
def invocation_blocks #:nodoc:
|
61
|
+
@invocation_blocks ||= from_superclass(:invocation_blocks, {})
|
62
|
+
end
|
63
|
+
|
64
|
+
# Invoke the given namespace or class given. It adds an instance
|
65
|
+
# method that will invoke the klass and task. You can give a block to
|
66
|
+
# configure how it will be invoked.
|
67
|
+
#
|
68
|
+
# The namespace/class given will have its options showed on the help
|
69
|
+
# usage. Check invoke_from_option for more information.
|
70
|
+
#
|
71
|
+
def invoke(*names, &block)
|
72
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
73
|
+
verbose = options.fetch(:verbose, true)
|
74
|
+
|
75
|
+
names.each do |name|
|
76
|
+
invocations[name] = false
|
77
|
+
invocation_blocks[name] = block if block_given?
|
78
|
+
|
79
|
+
class_eval <<-METHOD, __FILE__, __LINE__
|
80
|
+
def _invoke_#{name.to_s.gsub(/\W/, '_')}
|
81
|
+
klass, task = self.class.prepare_for_invocation(nil, #{name.inspect})
|
82
|
+
|
83
|
+
if klass
|
84
|
+
say_status :invoke, #{name.inspect}, #{verbose.inspect}
|
85
|
+
block = self.class.invocation_blocks[#{name.inspect}]
|
86
|
+
_invoke_for_class_method klass, task, &block
|
87
|
+
else
|
88
|
+
say_status :error, %(#{name.inspect} [not found]), :red
|
89
|
+
end
|
90
|
+
end
|
91
|
+
METHOD
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Invoke a thor class based on the value supplied by the user to the
|
96
|
+
# given option named "name". A class option must be created before this
|
97
|
+
# method is invoked for each name given.
|
98
|
+
#
|
99
|
+
# ==== Examples
|
100
|
+
#
|
101
|
+
# class GemGenerator < Thor::Group
|
102
|
+
# class_option :test_framework, :type => :string
|
103
|
+
# invoke_from_option :test_framework
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# ==== Boolean options
|
107
|
+
#
|
108
|
+
# In some cases, you want to invoke a thor class if some option is true or
|
109
|
+
# false. This is automatically handled by invoke_from_option. Then the
|
110
|
+
# option name is used to invoke the generator.
|
111
|
+
#
|
112
|
+
# ==== Preparing for invocation
|
113
|
+
#
|
114
|
+
# In some cases you want to customize how a specified hook is going to be
|
115
|
+
# invoked. You can do that by overwriting the class method
|
116
|
+
# prepare_for_invocation. The class method must necessarily return a klass
|
117
|
+
# and an optional task.
|
118
|
+
#
|
119
|
+
# ==== Custom invocations
|
120
|
+
#
|
121
|
+
# You can also supply a block to customize how the option is giong to be
|
122
|
+
# invoked. The block receives two parameters, an instance of the current
|
123
|
+
# class and the klass to be invoked.
|
124
|
+
#
|
125
|
+
def invoke_from_option(*names, &block)
|
126
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
127
|
+
verbose = options.fetch(:verbose, :white)
|
128
|
+
|
129
|
+
names.each do |name|
|
130
|
+
unless class_options.key?(name)
|
131
|
+
raise ArgumentError, "You have to define the option #{name.inspect} " <<
|
132
|
+
"before setting invoke_from_option."
|
133
|
+
end
|
134
|
+
|
135
|
+
invocations[name] = true
|
136
|
+
invocation_blocks[name] = block if block_given?
|
137
|
+
|
138
|
+
class_eval <<-METHOD, __FILE__, __LINE__
|
139
|
+
def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
|
140
|
+
return unless options[#{name.inspect}]
|
141
|
+
|
142
|
+
value = options[#{name.inspect}]
|
143
|
+
value = #{name.inspect} if TrueClass === value
|
144
|
+
klass, task = self.class.prepare_for_invocation(#{name.inspect}, value)
|
145
|
+
|
146
|
+
if klass
|
147
|
+
say_status :invoke, value, #{verbose.inspect}
|
148
|
+
block = self.class.invocation_blocks[#{name.inspect}]
|
149
|
+
_invoke_for_class_method klass, task, &block
|
150
|
+
else
|
151
|
+
say_status :error, %(\#{value} [not found]), :red
|
152
|
+
end
|
153
|
+
end
|
154
|
+
METHOD
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Remove a previously added invocation.
|
159
|
+
#
|
160
|
+
# ==== Examples
|
161
|
+
#
|
162
|
+
# remove_invocation :test_framework
|
163
|
+
#
|
164
|
+
def remove_invocation(*names)
|
165
|
+
names.each do |name|
|
166
|
+
remove_task(name)
|
167
|
+
remove_class_option(name)
|
168
|
+
invocations.delete(name)
|
169
|
+
invocation_blocks.delete(name)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Overwrite class options help to allow invoked generators options to be
|
174
|
+
# shown recursively when invoking a generator.
|
175
|
+
#
|
176
|
+
def class_options_help(shell, groups={}) #:nodoc:
|
177
|
+
get_options_from_invocations(groups, class_options) do |klass|
|
178
|
+
klass.send(:get_options_from_invocations, groups, class_options)
|
179
|
+
end
|
180
|
+
super(shell, groups)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Get invocations array and merge options from invocations. Those
|
184
|
+
# options are added to group_options hash. Options that already exists
|
185
|
+
# in base_options are not added twice.
|
186
|
+
#
|
187
|
+
def get_options_from_invocations(group_options, base_options) #:nodoc:
|
188
|
+
invocations.each do |name, from_option|
|
189
|
+
value = if from_option
|
190
|
+
option = class_options[name]
|
191
|
+
option.type == :boolean ? name : option.default
|
192
|
+
else
|
193
|
+
name
|
194
|
+
end
|
195
|
+
next unless value
|
196
|
+
|
197
|
+
klass, task = prepare_for_invocation(name, value)
|
198
|
+
next unless klass && klass.respond_to?(:class_options)
|
199
|
+
|
200
|
+
value = value.to_s
|
201
|
+
human_name = value.respond_to?(:classify) ? value.classify : value
|
202
|
+
|
203
|
+
group_options[human_name] ||= []
|
204
|
+
group_options[human_name] += klass.class_options.values.select do |option|
|
205
|
+
base_options[option.name.to_sym].nil? && option.group.nil? &&
|
206
|
+
!group_options.values.flatten.any? { |i| i.name == option.name }
|
207
|
+
end
|
208
|
+
|
209
|
+
yield klass if block_given?
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Returns tasks ready to be printed.
|
214
|
+
def printable_tasks(*)
|
215
|
+
item = []
|
216
|
+
item << banner
|
217
|
+
item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
|
218
|
+
[item]
|
219
|
+
end
|
220
|
+
|
221
|
+
protected
|
222
|
+
|
223
|
+
# The banner for this class. You can customize it if you are invoking the
|
224
|
+
# thor class by another ways which is not the Thor::Runner.
|
225
|
+
#
|
226
|
+
def banner
|
227
|
+
"thor #{self_task.formatted_usage(self, false)}"
|
228
|
+
end
|
229
|
+
|
230
|
+
# Represents the whole class as a task.
|
231
|
+
def self_task #:nodoc:
|
232
|
+
Thor::Task::Dynamic.new(self.namespace, class_options)
|
233
|
+
end
|
234
|
+
|
235
|
+
def baseclass #:nodoc:
|
236
|
+
Thor::Group
|
237
|
+
end
|
238
|
+
|
239
|
+
def create_task(meth) #:nodoc:
|
240
|
+
tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil)
|
241
|
+
true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
include Thor::Base
|
246
|
+
|
247
|
+
protected
|
248
|
+
|
249
|
+
# Shortcut to invoke with padding and block handling. Use internally by
|
250
|
+
# invoke and invoke_from_option class methods.
|
251
|
+
def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
|
252
|
+
shell.padding += 1
|
253
|
+
|
254
|
+
result = if block_given?
|
255
|
+
if block.arity == 2
|
256
|
+
block.call(self, klass)
|
257
|
+
else
|
258
|
+
block.call(self, klass, task)
|
259
|
+
end
|
260
|
+
else
|
261
|
+
invoke klass, task, *args
|
262
|
+
end
|
263
|
+
|
264
|
+
shell.padding -= 1
|
265
|
+
result
|
266
|
+
end
|
267
|
+
end
|