bundler 1.5.1 → 1.5.2
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/CHANGELOG.md +26 -2
- data/bin/bundle +1 -3
- data/bundler.gemspec +1 -1
- data/lib/bundler/cli.rb +2 -4
- data/lib/bundler/fetcher.rb +13 -12
- data/lib/bundler/installer.rb +9 -36
- data/lib/bundler/parallel_workers/unix_worker.rb +12 -4
- data/lib/bundler/parallel_workers/worker.rb +1 -0
- data/lib/bundler/rubygems_ext.rb +1 -1
- data/lib/bundler/rubygems_integration.rb +15 -8
- data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
- data/lib/bundler/vendor/thor.rb +63 -56
- data/lib/bundler/vendor/thor/actions.rb +52 -51
- data/lib/bundler/vendor/thor/actions/create_file.rb +35 -37
- data/lib/bundler/vendor/thor/actions/create_link.rb +1 -2
- data/lib/bundler/vendor/thor/actions/directory.rb +36 -37
- data/lib/bundler/vendor/thor/actions/empty_directory.rb +67 -69
- data/lib/bundler/vendor/thor/actions/file_manipulation.rb +11 -12
- data/lib/bundler/vendor/thor/actions/inject_into_file.rb +41 -43
- data/lib/bundler/vendor/thor/base.rb +180 -178
- data/lib/bundler/vendor/thor/command.rb +22 -25
- data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +21 -24
- data/lib/bundler/vendor/thor/core_ext/io_binary_read.rb +1 -3
- data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +8 -10
- data/lib/bundler/vendor/thor/error.rb +2 -2
- data/lib/bundler/vendor/thor/group.rb +59 -60
- data/lib/bundler/vendor/thor/invocation.rb +39 -38
- data/lib/bundler/vendor/thor/line_editor.rb +17 -0
- data/lib/bundler/vendor/thor/line_editor/basic.rb +35 -0
- data/lib/bundler/vendor/thor/line_editor/readline.rb +88 -0
- data/lib/bundler/vendor/thor/parser/argument.rb +29 -30
- data/lib/bundler/vendor/thor/parser/arguments.rb +102 -98
- data/lib/bundler/vendor/thor/parser/option.rb +25 -25
- data/lib/bundler/vendor/thor/parser/options.rb +85 -85
- data/lib/bundler/vendor/thor/rake_compat.rb +6 -7
- data/lib/bundler/vendor/thor/runner.rb +154 -154
- data/lib/bundler/vendor/thor/shell.rb +23 -30
- data/lib/bundler/vendor/thor/shell/basic.rb +66 -57
- data/lib/bundler/vendor/thor/shell/color.rb +44 -43
- data/lib/bundler/vendor/thor/shell/html.rb +43 -44
- data/lib/bundler/vendor/thor/util.rb +37 -40
- data/lib/bundler/vendor/thor/version.rb +1 -1
- data/lib/bundler/version.rb +1 -1
- data/man/bundle-install.ronn +1 -1
- data/man/gemfile.5.ronn +1 -2
- data/spec/commands/binstubs_spec.rb +13 -0
- data/spec/install/gemfile/git_spec.rb +2 -2
- data/spec/install/gems/dependency_api_spec.rb +34 -0
- data/spec/install/gems/packed_spec.rb +2 -4
- data/spec/quality_spec.rb +2 -2
- data/spec/realworld/parallel_spec.rb +69 -0
- data/spec/runtime/setup_spec.rb +3 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/support/artifice/endpoint_host_redirect.rb +15 -0
- data/spec/support/permissions.rb +11 -0
- metadata +11 -6
- data/spec/realworld/parallel_install_spec.rb +0 -23
- data/spec/realworld/parallel_update_spec.rb +0 -31
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 1.5.2 (2014-01-10)
|
2
|
+
|
3
|
+
Bugfixes:
|
4
|
+
|
5
|
+
- fix integration with Rubygems 1.8.0-1.8.19
|
6
|
+
- handle ENETDOWN exception during network requests
|
7
|
+
- gracefully shut down after interrupt during parallel install (@Who828)
|
8
|
+
- allow Rails to run Thor without debug mode (@rafaelfranca)
|
9
|
+
- set git binstub permissions by umask (@v-yarotsky)
|
10
|
+
- remove parallel install debug log
|
11
|
+
|
1
12
|
## 1.5.1 (2013-12-28)
|
2
13
|
|
3
14
|
Bugfixes:
|
@@ -96,12 +107,25 @@ Bugfixes:
|
|
96
107
|
- allow the same options hash to be passed to multiple gems (#2447)
|
97
108
|
- handle missing binaries without an exception (#2019, @luismreis)
|
98
109
|
|
99
|
-
## 1.3.6
|
110
|
+
## 1.3.6 (8 January 2014)
|
100
111
|
|
101
112
|
Bugfixes:
|
102
113
|
|
103
|
-
- set --no-cache when bundle install --local is called (@TimMoore)
|
104
114
|
- make gemspec path option preserve relative paths in lock file (@bwillis)
|
115
|
+
- use umask when creating binstubs (#1618, @v-yarotsky)
|
116
|
+
- warn if graphviz is not installed (#2435, @Agis-)
|
117
|
+
- show git errors while loading gemspecs
|
118
|
+
- don't mutate gem method options hash (#2447)
|
119
|
+
- print Thor errors (#2478, @pjvds)
|
120
|
+
- print Rubygems system exit errors (James Cook)
|
121
|
+
- more Pathnames into Strings for MacRuby (@kml)
|
122
|
+
- preserve original gemspec path (@bwillis)
|
123
|
+
- remove warning about deps with :git (#1651, @ixti)
|
124
|
+
- split git files on null (#2634, @jasonmp85)
|
125
|
+
- handle cross-host redirects without SSL (#2686, @grddev)
|
126
|
+
- handle Rubygems 2 security exception (@zzak)
|
127
|
+
- reinstall gems if they are missing with spec present
|
128
|
+
- set binstub permissions using umask (#1618, @v-yarotsky)
|
105
129
|
|
106
130
|
## 1.3.5 (3 April 2013)
|
107
131
|
|
data/bin/bundle
CHANGED
@@ -15,8 +15,6 @@ $LOAD_PATH.each do |path|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'bundler/cli'
|
18
|
-
# Force Thor to raise exceptions so we can exit non-zero.
|
19
|
-
ENV["THOR_DEBUG"] = "1"
|
20
18
|
|
21
19
|
require 'bundler/friendly_errors'
|
22
|
-
Bundler.with_friendly_errors { Bundler::CLI.start }
|
20
|
+
Bundler.with_friendly_errors { Bundler::CLI.start(ARGV, :debug => true) }
|
data/bundler.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.add_development_dependency 'ronn', '~> 0.7.3'
|
20
20
|
spec.add_development_dependency 'rspec', '~> 2.11'
|
21
21
|
|
22
|
-
spec.files = `git ls-files`.split(
|
22
|
+
spec.files = `git ls-files -z`.split("\x0")
|
23
23
|
spec.files += Dir.glob('lib/bundler/man/**/*') # man/ is ignored by git
|
24
24
|
spec.test_files = spec.files.grep(%r{^spec/})
|
25
25
|
|
data/lib/bundler/cli.rb
CHANGED
@@ -21,7 +21,7 @@ module Bundler
|
|
21
21
|
rescue UnknownArgumentError => e
|
22
22
|
raise InvalidOption, e.message
|
23
23
|
ensure
|
24
|
-
options ||= {}
|
24
|
+
self.options ||= {}
|
25
25
|
Bundler.ui = UI::Shell.new(options)
|
26
26
|
Bundler.ui.level = "debug" if options["verbose"]
|
27
27
|
end
|
@@ -232,8 +232,6 @@ module Bundler
|
|
232
232
|
opts[:system] = true
|
233
233
|
end
|
234
234
|
|
235
|
-
opts["no-cache"] ||= opts[:local]
|
236
|
-
|
237
235
|
Bundler.settings[:path] = nil if opts[:system]
|
238
236
|
Bundler.settings[:path] = "vendor/bundle" if opts[:deployment]
|
239
237
|
Bundler.settings[:path] = opts["path"] if opts["path"]
|
@@ -255,7 +253,7 @@ module Bundler
|
|
255
253
|
definition = Bundler.definition
|
256
254
|
definition.validate_ruby!
|
257
255
|
Installer.install(Bundler.root, definition, opts)
|
258
|
-
Bundler.load.cache if Bundler.root.join("vendor/cache").exist? && !
|
256
|
+
Bundler.load.cache if Bundler.root.join("vendor/cache").exist? && !options["no-cache"]
|
259
257
|
|
260
258
|
if Bundler.settings[:path]
|
261
259
|
absolute_path = File.expand_path(Bundler.settings[:path])
|
data/lib/bundler/fetcher.rb
CHANGED
@@ -226,7 +226,7 @@ module Bundler
|
|
226
226
|
private
|
227
227
|
|
228
228
|
HTTP_ERRORS = [
|
229
|
-
Timeout::Error, EOFError, SocketError,
|
229
|
+
Timeout::Error, EOFError, SocketError, Errno::ENETDOWN,
|
230
230
|
Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
|
231
231
|
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
|
232
232
|
Net::HTTP::Persistent::Error
|
@@ -235,17 +235,7 @@ module Bundler
|
|
235
235
|
def fetch(uri, counter = 0)
|
236
236
|
raise HTTPError, "Too many redirects" if counter >= @redirect_limit
|
237
237
|
|
238
|
-
|
239
|
-
Bundler.ui.debug "Fetching from: #{uri}"
|
240
|
-
req = Net::HTTP::Get.new uri.request_uri
|
241
|
-
req.basic_auth(uri.user, uri.password) if uri.user
|
242
|
-
response = connection.request(uri, req)
|
243
|
-
rescue OpenSSL::SSL::SSLError
|
244
|
-
raise CertificateFailureError.new(uri)
|
245
|
-
rescue *HTTP_ERRORS
|
246
|
-
raise HTTPError, "Network error while fetching #{uri}"
|
247
|
-
end
|
248
|
-
|
238
|
+
response = request(uri)
|
249
239
|
case response
|
250
240
|
when Net::HTTPRedirection
|
251
241
|
Bundler.ui.debug("HTTP Redirection")
|
@@ -265,6 +255,17 @@ module Bundler
|
|
265
255
|
end
|
266
256
|
end
|
267
257
|
|
258
|
+
def request(uri)
|
259
|
+
Bundler.ui.debug "Fetching from: #{uri}"
|
260
|
+
req = Net::HTTP::Get.new uri.request_uri
|
261
|
+
req.basic_auth(uri.user, uri.password) if uri.user
|
262
|
+
response = connection.request(uri, req)
|
263
|
+
rescue OpenSSL::SSL::SSLError
|
264
|
+
raise CertificateFailureError.new(uri)
|
265
|
+
rescue *HTTP_ERRORS
|
266
|
+
raise HTTPError, "Network error while fetching #{uri}"
|
267
|
+
end
|
268
|
+
|
268
269
|
def dependency_api_uri(gem_names = [])
|
269
270
|
url = "#{@remote_uri}api/v1/dependencies"
|
270
271
|
url << "?gems=#{URI.encode(gem_names.join(","))}" if gem_names.any?
|
data/lib/bundler/installer.rb
CHANGED
@@ -113,7 +113,6 @@ module Bundler
|
|
113
113
|
Bundler.ui.debug debug_message if debug_message
|
114
114
|
spec_info = "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
|
115
115
|
Bundler.ui.debug spec_info
|
116
|
-
logger.info spec_info
|
117
116
|
end
|
118
117
|
|
119
118
|
if Bundler.settings[:bin] && standalone
|
@@ -139,7 +138,6 @@ module Bundler
|
|
139
138
|
msg << " #{spec.name} -v '#{spec.version}'` succeeds before bundling."
|
140
139
|
end
|
141
140
|
Bundler.ui.debug e.backtrace.join("\n")
|
142
|
-
logger.error("#{e.class}: #{e.message}\n#{e.backtrace.join(' \n')}")
|
143
141
|
raise Bundler::InstallError, msg
|
144
142
|
end
|
145
143
|
|
@@ -176,7 +174,7 @@ module Bundler
|
|
176
174
|
next
|
177
175
|
end
|
178
176
|
|
179
|
-
File.open(binstub_path, 'w',
|
177
|
+
File.open(binstub_path, 'w', 0777 & ~File.umask) do |f|
|
180
178
|
f.puts ERB.new(template, nil, '-').result(binding)
|
181
179
|
end
|
182
180
|
end
|
@@ -198,15 +196,6 @@ module Bundler
|
|
198
196
|
|
199
197
|
private
|
200
198
|
|
201
|
-
def logger
|
202
|
-
# Create a debug installation log limited to 1MB
|
203
|
-
@logger ||= begin
|
204
|
-
require 'logger'
|
205
|
-
Bundler.app_config_path.mkpath
|
206
|
-
Logger.new(Bundler.app_config_path.join("install.log"), 1, 1048576)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
199
|
def can_install_parallely?
|
211
200
|
min_rubygems = "2.0.7"
|
212
201
|
if Bundler.current_ruby.mri? || Bundler.rubygems.provides?(">= #{min_rubygems}")
|
@@ -219,25 +208,6 @@ module Bundler
|
|
219
208
|
end
|
220
209
|
end
|
221
210
|
|
222
|
-
def check_rubygems_cache_dir
|
223
|
-
require 'digest'
|
224
|
-
cached_gems = Dir["#{Bundler.rubygems.gem_dir}/cache/*.gem"]
|
225
|
-
|
226
|
-
same_size_gems = cached_gems.group_by { |f| File.size(f) }.
|
227
|
-
values.select { |names| names.size > 1 }
|
228
|
-
|
229
|
-
same_hash_gems = same_size_gems.flatten.group_by do |f|
|
230
|
-
Digest::SHA1.hexdigest(File.read(f))
|
231
|
-
end.values.select { |names| names.size > 1 }
|
232
|
-
|
233
|
-
if same_hash_gems.any?
|
234
|
-
Bundler.ui.warn "It looks like some of your gems are corrupted!"
|
235
|
-
same_hash_gems.each { |name| Bundler.ui.warn " * #{name}" }
|
236
|
-
Bundler.ui.warn "Please report this issue to the Bundler issue tracker " \
|
237
|
-
"on Github, and include the log file at .bundle/install.log. Thanks!"
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
211
|
def generate_standalone_bundler_executable_stubs(spec)
|
242
212
|
# double-assignment to avoid warnings about variables that will be used by ERB
|
243
213
|
bin_path = Bundler.bin_path
|
@@ -314,8 +284,7 @@ module Bundler
|
|
314
284
|
{ :name => spec.name, :post_install => message }
|
315
285
|
}
|
316
286
|
specs.each do |spec|
|
317
|
-
|
318
|
-
if deps.empty?
|
287
|
+
if ready_to_install?(spec, remains)
|
319
288
|
worker_pool.enq spec.name
|
320
289
|
enqueued[spec.name] = true
|
321
290
|
end
|
@@ -330,17 +299,21 @@ module Bundler
|
|
330
299
|
remains.keys.each do |name|
|
331
300
|
next if enqueued[name]
|
332
301
|
spec = name2spec[name]
|
333
|
-
|
334
|
-
if deps.empty?
|
302
|
+
if ready_to_install?(spec, remains)
|
335
303
|
worker_pool.enq name
|
336
304
|
enqueued[name] = true
|
337
305
|
end
|
338
306
|
end
|
339
307
|
end
|
340
|
-
check_rubygems_cache_dir
|
341
308
|
message
|
342
309
|
ensure
|
343
310
|
worker_pool && worker_pool.stop
|
344
311
|
end
|
312
|
+
|
313
|
+
def ready_to_install?(spec, remains)
|
314
|
+
spec.dependencies.none? do |dep|
|
315
|
+
remains[dep.name] && dep.type != :development && dep.name != spec.name
|
316
|
+
end
|
317
|
+
end
|
345
318
|
end
|
346
319
|
end
|
@@ -80,12 +80,20 @@ module Bundler
|
|
80
80
|
# Kill the forked workers by sending SIGINT to them
|
81
81
|
def stop_workers
|
82
82
|
@workers.each do |worker|
|
83
|
-
worker.io_r.close
|
84
|
-
worker.io_w.close
|
85
|
-
|
83
|
+
worker.io_r.close unless worker.io_r.closed?
|
84
|
+
worker.io_w.close unless worker.io_w.closed?
|
85
|
+
begin
|
86
|
+
Process.kill :INT, worker.pid
|
87
|
+
rescue Errno::ESRCH
|
88
|
+
nil
|
89
|
+
end
|
86
90
|
end
|
87
91
|
@workers.each do |worker|
|
88
|
-
|
92
|
+
begin
|
93
|
+
Process.waitpid worker.pid
|
94
|
+
rescue Errno::ECHILD
|
95
|
+
nil
|
96
|
+
end
|
89
97
|
end
|
90
98
|
end
|
91
99
|
end
|
data/lib/bundler/rubygems_ext.rb
CHANGED
@@ -56,7 +56,7 @@ module Gem
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def git_version
|
59
|
-
if
|
59
|
+
if loaded_from && File.exist?(File.join(full_gem_path, ".git"))
|
60
60
|
sha = Bundler::SharedHelpers.chdir(full_gem_path){ `git rev-parse HEAD`.strip }
|
61
61
|
" #{sha[0..6]}"
|
62
62
|
end
|
@@ -422,7 +422,7 @@ module Bundler
|
|
422
422
|
end
|
423
423
|
end
|
424
424
|
|
425
|
-
# Rubygems
|
425
|
+
# Rubygems 1.8.5-1.8.19
|
426
426
|
class Modern < RubygemsIntegration
|
427
427
|
def stub_rubygems(specs)
|
428
428
|
Gem::Specification.all = specs
|
@@ -441,11 +441,6 @@ module Bundler
|
|
441
441
|
def find_name(name)
|
442
442
|
Gem::Specification.find_all_by_name name
|
443
443
|
end
|
444
|
-
|
445
|
-
def build(spec, skip_validation = false)
|
446
|
-
require 'rubygems/builder'
|
447
|
-
Gem::Builder.new(spec).build(skip_validation)
|
448
|
-
end
|
449
444
|
end
|
450
445
|
|
451
446
|
# Rubygems 1.8.0 to 1.8.4
|
@@ -460,14 +455,24 @@ module Bundler
|
|
460
455
|
end
|
461
456
|
end
|
462
457
|
|
458
|
+
# Rubygems 1.8.20+
|
459
|
+
class MoreModern < Modern
|
460
|
+
# Rubygems 1.8.20 and adds the skip_validation parameter, so that's
|
461
|
+
# when we start passing it through.
|
462
|
+
def build(spec, skip_validation = false)
|
463
|
+
require 'rubygems/builder'
|
464
|
+
Gem::Builder.new(spec).build(skip_validation)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
463
468
|
# Rubygems 2.0
|
464
469
|
class Future < RubygemsIntegration
|
465
470
|
def stub_rubygems(specs)
|
466
471
|
Gem::Specification.all = specs
|
467
472
|
|
468
|
-
Gem.post_reset
|
473
|
+
Gem.post_reset do
|
469
474
|
Gem::Specification.all = specs
|
470
|
-
|
475
|
+
end
|
471
476
|
end
|
472
477
|
|
473
478
|
def all_specs
|
@@ -529,6 +534,8 @@ module Bundler
|
|
529
534
|
|
530
535
|
if RubygemsIntegration.provides?(">= 1.99.99")
|
531
536
|
@rubygems = RubygemsIntegration::Future.new
|
537
|
+
elsif RubygemsIntegration.provides?('>= 1.8.20')
|
538
|
+
@rubygems = RubygemsIntegration::MoreModern.new
|
532
539
|
elsif RubygemsIntegration.provides?('>= 1.8.5')
|
533
540
|
@rubygems = RubygemsIntegration::Modern.new
|
534
541
|
elsif RubygemsIntegration.provides?('>= 1.8.0')
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = ""
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
data/lib/bundler/vendor/thor.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'thor/base'
|
3
3
|
|
4
|
-
class Thor
|
4
|
+
class Thor # rubocop:disable ClassLength
|
5
5
|
class << self
|
6
6
|
# Allows for custom "Command" package naming.
|
7
7
|
#
|
@@ -9,7 +9,7 @@ class Thor
|
|
9
9
|
# name<String>
|
10
10
|
# options<Hash>
|
11
11
|
#
|
12
|
-
def package_name(name, options={})
|
12
|
+
def package_name(name, options = {})
|
13
13
|
@package_name = name.nil? || name == '' ? nil : name
|
14
14
|
end
|
15
15
|
|
@@ -18,17 +18,14 @@ class Thor
|
|
18
18
|
# ==== Parameters
|
19
19
|
# meth<Symbol>:: name of the default command
|
20
20
|
#
|
21
|
-
def default_command(meth=nil)
|
22
|
-
|
23
|
-
|
24
|
-
'help'
|
25
|
-
when nil
|
26
|
-
@default_command || from_superclass(:default_command, 'help')
|
21
|
+
def default_command(meth = nil)
|
22
|
+
if meth
|
23
|
+
@default_command = meth == :none ? 'help' : meth.to_s
|
27
24
|
else
|
28
|
-
|
25
|
+
@default_command ||= from_superclass(:default_command, 'help')
|
29
26
|
end
|
30
27
|
end
|
31
|
-
|
28
|
+
alias_method :default_task, :default_command
|
32
29
|
|
33
30
|
# Registers another Thor subclass as a command.
|
34
31
|
#
|
@@ -37,7 +34,7 @@ class Thor
|
|
37
34
|
# command<String>:: Subcommand name to use
|
38
35
|
# usage<String>:: Short usage for the subcommand
|
39
36
|
# description<String>:: Description for the subcommand
|
40
|
-
def register(klass, subcommand_name, usage, description, options={})
|
37
|
+
def register(klass, subcommand_name, usage, description, options = {})
|
41
38
|
if klass <= Thor::Group
|
42
39
|
desc usage, description, options
|
43
40
|
define_method(subcommand_name) { |*args| invoke(klass, args) }
|
@@ -54,7 +51,7 @@ class Thor
|
|
54
51
|
# description<String>
|
55
52
|
# options<String>
|
56
53
|
#
|
57
|
-
def desc(usage, description, options={})
|
54
|
+
def desc(usage, description, options = {})
|
58
55
|
if options[:for]
|
59
56
|
command = find_and_refresh_command(options[:for])
|
60
57
|
command.usage = usage if usage
|
@@ -69,7 +66,7 @@ class Thor
|
|
69
66
|
# ==== Parameters
|
70
67
|
# long description<String>
|
71
68
|
#
|
72
|
-
def long_desc(long_description, options={})
|
69
|
+
def long_desc(long_description, options = {})
|
73
70
|
if options[:for]
|
74
71
|
command = find_and_refresh_command(options[:for])
|
75
72
|
command.long_description = long_description if long_description
|
@@ -91,13 +88,13 @@ class Thor
|
|
91
88
|
# ==== Parameters
|
92
89
|
# Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
|
93
90
|
#
|
94
|
-
def map(mappings=nil)
|
91
|
+
def map(mappings = nil)
|
95
92
|
@map ||= from_superclass(:map, {})
|
96
93
|
|
97
94
|
if mappings
|
98
95
|
mappings.each do |key, value|
|
99
96
|
if key.respond_to?(:each)
|
100
|
-
key.each {|subkey| @map[subkey] = value}
|
97
|
+
key.each { |subkey| @map[subkey] = value }
|
101
98
|
else
|
102
99
|
@map[key] = value
|
103
100
|
end
|
@@ -114,13 +111,13 @@ class Thor
|
|
114
111
|
# is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
|
115
112
|
# or :required (string). If you give a value, the type of the value is used.
|
116
113
|
#
|
117
|
-
def method_options(options=nil)
|
114
|
+
def method_options(options = nil)
|
118
115
|
@method_options ||= {}
|
119
116
|
build_options(options, @method_options) if options
|
120
117
|
@method_options
|
121
118
|
end
|
122
119
|
|
123
|
-
|
120
|
+
alias_method :options, :method_options
|
124
121
|
|
125
122
|
# Adds an option to the set of method options. If :for is given as option,
|
126
123
|
# it allows you to change the options from a previous defined command.
|
@@ -148,16 +145,16 @@ class Thor
|
|
148
145
|
# :banner - String to show on usage notes.
|
149
146
|
# :hide - If you want to hide this option from the help.
|
150
147
|
#
|
151
|
-
def method_option(name, options={})
|
148
|
+
def method_option(name, options = {})
|
152
149
|
scope = if options[:for]
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
find_and_refresh_command(options[:for]).options
|
151
|
+
else
|
152
|
+
method_options
|
153
|
+
end
|
157
154
|
|
158
155
|
build_option(name, options, scope)
|
159
156
|
end
|
160
|
-
|
157
|
+
alias_method :option, :method_option
|
161
158
|
|
162
159
|
# Prints help information for the given command.
|
163
160
|
#
|
@@ -170,18 +167,18 @@ class Thor
|
|
170
167
|
command = all_commands[meth]
|
171
168
|
handle_no_command_error(meth) unless command
|
172
169
|
|
173
|
-
shell.say
|
170
|
+
shell.say 'Usage:'
|
174
171
|
shell.say " #{banner(command)}"
|
175
172
|
shell.say
|
176
173
|
class_options_help(shell, nil => command.options.map { |_, o| o })
|
177
174
|
if command.long_description
|
178
|
-
shell.say
|
175
|
+
shell.say 'Description:'
|
179
176
|
shell.print_wrapped(command.long_description, :indent => 2)
|
180
177
|
else
|
181
178
|
shell.say command.description
|
182
179
|
end
|
183
180
|
end
|
184
|
-
|
181
|
+
alias_method :task_help, :command_help
|
185
182
|
|
186
183
|
# Prints help information for this class.
|
187
184
|
#
|
@@ -193,12 +190,12 @@ class Thor
|
|
193
190
|
Thor::Util.thor_classes_in(self).each do |klass|
|
194
191
|
list += klass.printable_commands(false)
|
195
192
|
end
|
196
|
-
list.sort!{ |a,b| a[0] <=> b[0] }
|
193
|
+
list.sort! { |a, b| a[0] <=> b[0] }
|
197
194
|
|
198
|
-
if @package_name
|
195
|
+
if defined?(@package_name) && @package_name
|
199
196
|
shell.say "#{@package_name} commands:"
|
200
197
|
else
|
201
|
-
shell.say
|
198
|
+
shell.say 'Commands:'
|
202
199
|
end
|
203
200
|
|
204
201
|
shell.print_table(list, :indent => 2, :truncate => true)
|
@@ -212,34 +209,35 @@ class Thor
|
|
212
209
|
next if command.hidden?
|
213
210
|
item = []
|
214
211
|
item << banner(command, false, subcommand)
|
215
|
-
item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" :
|
212
|
+
item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : '')
|
216
213
|
item
|
217
214
|
end.compact
|
218
215
|
end
|
219
|
-
|
216
|
+
alias_method :printable_tasks, :printable_commands
|
220
217
|
|
221
218
|
def subcommands
|
222
219
|
@subcommands ||= from_superclass(:subcommands, [])
|
223
220
|
end
|
224
|
-
|
221
|
+
alias_method :subtasks, :subcommands
|
225
222
|
|
226
223
|
def subcommand(subcommand, subcommand_class)
|
227
|
-
|
224
|
+
subcommands << subcommand.to_s
|
228
225
|
subcommand_class.subcommand_help subcommand
|
229
226
|
|
230
227
|
define_method(subcommand) do |*args|
|
231
228
|
args, opts = Thor::Arguments.split(args)
|
229
|
+
args.unshift("help") if opts.include? "--help" or opts.include? "-h"
|
232
230
|
invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
|
233
231
|
end
|
234
232
|
end
|
235
|
-
|
233
|
+
alias_method :subtask, :subcommand
|
236
234
|
|
237
235
|
# Extend check unknown options to accept a hash of conditions.
|
238
236
|
#
|
239
237
|
# === Parameters
|
240
238
|
# options<Hash>: A hash containing :only and/or :except keys
|
241
|
-
def check_unknown_options!(options={})
|
242
|
-
@check_unknown_options ||=
|
239
|
+
def check_unknown_options!(options = {})
|
240
|
+
@check_unknown_options ||= {}
|
243
241
|
options.each do |key, value|
|
244
242
|
if value
|
245
243
|
@check_unknown_options[key] = Array(value)
|
@@ -309,18 +307,20 @@ class Thor
|
|
309
307
|
# ==== Parameters
|
310
308
|
# Symbol ...:: A list of commands that should be affected.
|
311
309
|
def stop_on_unknown_option!(*command_names)
|
312
|
-
|
313
|
-
@stop_on_unknown_option.merge(command_names)
|
310
|
+
stop_on_unknown_option.merge(command_names)
|
314
311
|
end
|
315
312
|
|
316
313
|
def stop_on_unknown_option?(command) #:nodoc:
|
317
|
-
command &&
|
314
|
+
command && stop_on_unknown_option.include?(command.name.to_sym)
|
318
315
|
end
|
319
316
|
|
320
317
|
protected
|
318
|
+
def stop_on_unknown_option #:nodoc:
|
319
|
+
@stop_on_unknown_option ||= Set.new
|
320
|
+
end
|
321
321
|
|
322
322
|
# The method responsible for dispatching given the args.
|
323
|
-
def dispatch(meth, given_args, given_opts, config) #:nodoc:
|
323
|
+
def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
|
324
324
|
# There is an edge case when dispatching from a subcommand.
|
325
325
|
# A problem occurs invoking the default command. This case occurs
|
326
326
|
# when arguments are passed and a default command is defined, and
|
@@ -331,7 +331,7 @@ class Thor
|
|
331
331
|
# the command normally. If the first item in given_args is not
|
332
332
|
# a command then use the default command. The given_args will be
|
333
333
|
# intact later since dup was used.
|
334
|
-
if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command !=
|
334
|
+
if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != 'help' && given_args.first != default_command
|
335
335
|
meth ||= retrieve_command_name(given_args.dup)
|
336
336
|
command = all_commands[normalize_command_name(meth)]
|
337
337
|
command ||= all_commands[normalize_command_name(default_command)]
|
@@ -350,7 +350,7 @@ class Thor
|
|
350
350
|
end
|
351
351
|
else
|
352
352
|
args, opts = given_args, nil
|
353
|
-
command =
|
353
|
+
command = dynamic_command_class.new(meth)
|
354
354
|
end
|
355
355
|
|
356
356
|
opts = given_opts || opts || []
|
@@ -376,22 +376,30 @@ class Thor
|
|
376
376
|
Thor
|
377
377
|
end
|
378
378
|
|
379
|
+
def dynamic_command_class #:nodoc:
|
380
|
+
Thor::DynamicCommand
|
381
|
+
end
|
382
|
+
|
379
383
|
def create_command(meth) #:nodoc:
|
384
|
+
@usage ||= nil
|
385
|
+
@desc ||= nil
|
386
|
+
@long_desc ||= nil
|
387
|
+
|
380
388
|
if @usage && @desc
|
381
389
|
base_class = @hide ? Thor::HiddenCommand : Thor::Command
|
382
390
|
commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
|
383
391
|
@usage, @desc, @long_desc, @method_options, @hide = nil
|
384
392
|
true
|
385
|
-
elsif
|
393
|
+
elsif all_commands[meth] || meth == 'method_missing'
|
386
394
|
true
|
387
395
|
else
|
388
396
|
puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
|
389
|
-
|
397
|
+
'Call desc if you want this method to be available as command or declare it inside a ' <<
|
390
398
|
"no_commands{} block. Invoked from #{caller[1].inspect}."
|
391
399
|
false
|
392
400
|
end
|
393
401
|
end
|
394
|
-
|
402
|
+
alias_method :create_task, :create_command
|
395
403
|
|
396
404
|
def initialize_added #:nodoc:
|
397
405
|
class_options.merge!(method_options)
|
@@ -407,7 +415,7 @@ class Thor
|
|
407
415
|
nil
|
408
416
|
end
|
409
417
|
end
|
410
|
-
|
418
|
+
alias_method :retrieve_task_name, :retrieve_command_name
|
411
419
|
|
412
420
|
# receives a (possibly nil) command name and returns a name that is in
|
413
421
|
# the commands hash. In addition to normalizing aliases, this logic
|
@@ -421,7 +429,7 @@ class Thor
|
|
421
429
|
|
422
430
|
possibilities = find_command_possibilities(meth)
|
423
431
|
if possibilities.size > 1
|
424
|
-
|
432
|
+
fail AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
|
425
433
|
elsif possibilities.size < 1
|
426
434
|
meth = meth || default_command
|
427
435
|
elsif map[meth]
|
@@ -430,9 +438,9 @@ class Thor
|
|
430
438
|
meth = possibilities.first
|
431
439
|
end
|
432
440
|
|
433
|
-
meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
|
441
|
+
meth.to_s.gsub('-', '_') # treat foo-bar as foo_bar
|
434
442
|
end
|
435
|
-
|
443
|
+
alias_method :normalize_task_name, :normalize_command_name
|
436
444
|
|
437
445
|
# this is the logic that takes the command name passed in by the user
|
438
446
|
# and determines whether it is an unambiguous substrings of a command or
|
@@ -450,23 +458,22 @@ class Thor
|
|
450
458
|
possibilities
|
451
459
|
end
|
452
460
|
end
|
453
|
-
|
461
|
+
alias_method :find_task_possibilities, :find_command_possibilities
|
454
462
|
|
455
463
|
def subcommand_help(cmd)
|
456
|
-
desc
|
457
|
-
class_eval
|
464
|
+
desc 'help [COMMAND]', 'Describe subcommands or one specific subcommand'
|
465
|
+
class_eval "
|
458
466
|
def help(command = nil, subcommand = true); super; end
|
459
|
-
|
467
|
+
"
|
460
468
|
end
|
461
|
-
|
462
|
-
|
469
|
+
alias_method :subtask_help, :subcommand_help
|
463
470
|
end
|
464
471
|
|
465
472
|
include Thor::Base
|
466
473
|
|
467
474
|
map HELP_MAPPINGS => :help
|
468
475
|
|
469
|
-
desc
|
476
|
+
desc 'help [COMMAND]', 'Describe available commands or one specific command'
|
470
477
|
def help(command = nil, subcommand = false)
|
471
478
|
command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
|
472
479
|
end
|