bundler 1.5.1 → 1.5.2
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/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
@@ -4,7 +4,7 @@ class Thor
|
|
4
4
|
|
5
5
|
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
6
6
|
|
7
|
-
def initialize(name, options={})
|
7
|
+
def initialize(name, options = {})
|
8
8
|
options[:required] = false unless options.key?(:required)
|
9
9
|
super
|
10
10
|
@lazy_default = options[:lazy_default]
|
@@ -40,7 +40,7 @@ class Thor
|
|
40
40
|
#
|
41
41
|
# By default all options are optional, unless :required is given.
|
42
42
|
#
|
43
|
-
def self.parse(key, value)
|
43
|
+
def self.parse(key, value) # rubocop:disable MethodLength
|
44
44
|
if key.is_a?(Array)
|
45
45
|
name, *aliases = key
|
46
46
|
else
|
@@ -51,21 +51,21 @@ class Thor
|
|
51
51
|
default = value
|
52
52
|
|
53
53
|
type = case value
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
54
|
+
when Symbol
|
55
|
+
default = nil
|
56
|
+
if VALID_TYPES.include?(value)
|
57
|
+
value
|
58
|
+
elsif required = (value == :required) # rubocop:disable AssignmentInCondition
|
59
|
+
:string
|
60
|
+
end
|
61
|
+
when TrueClass, FalseClass
|
62
|
+
:boolean
|
63
|
+
when Numeric
|
64
|
+
:numeric
|
65
|
+
when Hash, Array, String
|
66
|
+
value.class.name.downcase.to_sym
|
67
|
+
end
|
68
|
+
new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases)
|
69
69
|
end
|
70
70
|
|
71
71
|
def switch_name
|
@@ -76,17 +76,17 @@ class Thor
|
|
76
76
|
@human_name ||= dasherized? ? undasherize(name) : name
|
77
77
|
end
|
78
78
|
|
79
|
-
def usage(padding=0)
|
79
|
+
def usage(padding = 0)
|
80
80
|
sample = if banner && !banner.to_s.empty?
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
"#{switch_name}=#{banner}"
|
82
|
+
else
|
83
|
+
switch_name
|
84
|
+
end
|
85
85
|
|
86
86
|
sample = "[#{sample}]" unless required?
|
87
87
|
|
88
88
|
if aliases.empty?
|
89
|
-
(
|
89
|
+
(' ' * padding) << sample
|
90
90
|
else
|
91
91
|
"#{aliases.join(', ')}, #{sample}"
|
92
92
|
end
|
@@ -103,7 +103,7 @@ class Thor
|
|
103
103
|
protected
|
104
104
|
|
105
105
|
def validate!
|
106
|
-
|
106
|
+
fail ArgumentError, 'An option cannot be boolean and required.' if boolean? && required?
|
107
107
|
end
|
108
108
|
|
109
109
|
def dasherized?
|
@@ -115,7 +115,7 @@ class Thor
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def dasherize(str)
|
118
|
-
(str.length > 1 ?
|
118
|
+
(str.length > 1 ? '--' : '-') + str.gsub('_', '-')
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Thor
|
2
|
-
class Options < Arguments #:nodoc:
|
2
|
+
class Options < Arguments #:nodoc: # rubocop:disable ClassLength
|
3
3
|
LONG_RE = /^(--\w+(?:-\w+)*)$/
|
4
4
|
SHORT_RE = /^(-[a-z])$/i
|
5
5
|
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
|
@@ -14,22 +14,22 @@ class Thor
|
|
14
14
|
when true
|
15
15
|
"--#{key}"
|
16
16
|
when Array
|
17
|
-
"--#{key} #{value.map{ |v| v.inspect }.join(' ')}"
|
17
|
+
"--#{key} #{value.map { |v| v.inspect }.join(' ')}"
|
18
18
|
when Hash
|
19
|
-
"--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}"
|
19
|
+
"--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}"
|
20
20
|
when nil, false
|
21
|
-
|
21
|
+
''
|
22
22
|
else
|
23
23
|
"--#{key} #{value.inspect}"
|
24
24
|
end
|
25
|
-
end.join(
|
25
|
+
end.join(' ')
|
26
26
|
end
|
27
27
|
|
28
28
|
# Takes a hash of Thor::Option and a hash with defaults.
|
29
29
|
#
|
30
30
|
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
|
31
31
|
# an unknown option or a regular argument.
|
32
|
-
def initialize(hash_options={}, defaults={}, stop_on_unknown=false)
|
32
|
+
def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false)
|
33
33
|
@stop_on_unknown = stop_on_unknown
|
34
34
|
options = hash_options.values
|
35
35
|
super(options)
|
@@ -52,7 +52,7 @@ class Thor
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def remaining
|
55
|
+
def remaining # rubocop:disable TrivialAccessors
|
56
56
|
@extra
|
57
57
|
end
|
58
58
|
|
@@ -69,7 +69,7 @@ class Thor
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def parse(args)
|
72
|
+
def parse(args) # rubocop:disable MethodLength
|
73
73
|
@pile = args.dup
|
74
74
|
@parsing_options = true
|
75
75
|
|
@@ -119,100 +119,100 @@ class Thor
|
|
119
119
|
def check_unknown!
|
120
120
|
# an unknown option starts with - or -- and has no more --'s afterward.
|
121
121
|
unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
|
122
|
-
|
122
|
+
fail UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
|
123
123
|
end
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
# Check if the current value in peek is a registered switch.
|
128
|
-
#
|
129
|
-
# Two booleans are returned. The first is true if the current value
|
130
|
-
# starts with a hyphen; the second is true if it is a registered switch.
|
131
|
-
def current_is_switch?
|
132
|
-
case peek
|
133
|
-
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
134
|
-
[true, switch?($1)]
|
135
|
-
when SHORT_SQ_RE
|
136
|
-
[true, $1.split('').any? { |f| switch?("-#{f}") }]
|
137
|
-
else
|
138
|
-
[false, false]
|
139
|
-
end
|
140
|
-
end
|
125
|
+
protected
|
141
126
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
127
|
+
# Check if the current value in peek is a registered switch.
|
128
|
+
#
|
129
|
+
# Two booleans are returned. The first is true if the current value
|
130
|
+
# starts with a hyphen; the second is true if it is a registered switch.
|
131
|
+
def current_is_switch?
|
132
|
+
case peek
|
133
|
+
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
134
|
+
[true, switch?($1)]
|
135
|
+
when SHORT_SQ_RE
|
136
|
+
[true, $1.split('').any? { |f| switch?("-#{f}") }]
|
137
|
+
else
|
138
|
+
[false, false]
|
149
139
|
end
|
140
|
+
end
|
150
141
|
|
151
|
-
|
152
|
-
|
142
|
+
def current_is_switch_formatted?
|
143
|
+
case peek
|
144
|
+
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
|
145
|
+
true
|
146
|
+
else
|
147
|
+
false
|
153
148
|
end
|
149
|
+
end
|
154
150
|
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
def current_is_value?
|
152
|
+
peek && (!parsing_options? || super)
|
153
|
+
end
|
158
154
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
else
|
163
|
-
@switches[arg]
|
164
|
-
end
|
165
|
-
end
|
155
|
+
def switch?(arg)
|
156
|
+
switch_option(normalize_switch(arg))
|
157
|
+
end
|
166
158
|
|
167
|
-
|
168
|
-
#
|
169
|
-
|
170
|
-
|
159
|
+
def switch_option(arg)
|
160
|
+
if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
|
161
|
+
@switches[arg] || @switches["--#{match}"]
|
162
|
+
else
|
163
|
+
@switches[arg]
|
171
164
|
end
|
165
|
+
end
|
172
166
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
167
|
+
# Check if the given argument is actually a shortcut.
|
168
|
+
#
|
169
|
+
def normalize_switch(arg)
|
170
|
+
(@shorts[arg] || arg).tr('_', '-')
|
171
|
+
end
|
177
172
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
173
|
+
def parsing_options?
|
174
|
+
peek
|
175
|
+
@parsing_options
|
176
|
+
end
|
177
|
+
|
178
|
+
# Parse boolean values which can be given as --foo=true, --foo or --no-foo.
|
179
|
+
#
|
180
|
+
def parse_boolean(switch)
|
181
|
+
if current_is_value?
|
182
|
+
if ['true', 'TRUE', 't', 'T', true].include?(peek)
|
183
|
+
shift
|
184
|
+
true
|
185
|
+
elsif ['false', 'FALSE', 'f', 'F', false].include?(peek)
|
186
|
+
shift
|
187
|
+
false
|
191
188
|
else
|
192
|
-
|
189
|
+
true
|
193
190
|
end
|
191
|
+
else
|
192
|
+
@switches.key?(switch) || !no_or_skip?(switch)
|
194
193
|
end
|
194
|
+
end
|
195
195
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
end
|
196
|
+
# Parse the value at the peek analyzing if it requires an input or not.
|
197
|
+
#
|
198
|
+
def parse_peek(switch, option)
|
199
|
+
if parsing_options? && (current_is_switch_formatted? || last?)
|
200
|
+
if option.boolean?
|
201
|
+
# No problem for boolean types
|
202
|
+
elsif no_or_skip?(switch)
|
203
|
+
return nil # User set value to nil
|
204
|
+
elsif option.string? && !option.required?
|
205
|
+
# Return the default if there is one, else the human name
|
206
|
+
return option.lazy_default || option.default || option.human_name
|
207
|
+
elsif option.lazy_default
|
208
|
+
return option.lazy_default
|
209
|
+
else
|
210
|
+
fail MalformattedArgumentError, "No value provided for option '#{switch}'"
|
212
211
|
end
|
213
|
-
|
214
|
-
@non_assigned_required.delete(option)
|
215
|
-
send(:"parse_#{option.type}", switch)
|
216
212
|
end
|
213
|
+
|
214
|
+
@non_assigned_required.delete(option)
|
215
|
+
send(:"parse_#{option.type}", switch)
|
216
|
+
end
|
217
217
|
end
|
218
218
|
end
|
@@ -12,7 +12,7 @@ class Thor
|
|
12
12
|
# include Thor::RakeCompat
|
13
13
|
#
|
14
14
|
# RSpec::Core::RakeTask.new(:spec) do |t|
|
15
|
-
# t.spec_opts = ['--options',
|
15
|
+
# t.spec_opts = ['--options', './.rspec']
|
16
16
|
# t.spec_files = FileList['spec/**/*_spec.rb']
|
17
17
|
# end
|
18
18
|
# end
|
@@ -28,23 +28,23 @@ class Thor
|
|
28
28
|
# Hack. Make rakefile point to invoker, so rdoc task is generated properly.
|
29
29
|
rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
|
30
30
|
Rake.application.instance_variable_set(:@rakefile, rakefile)
|
31
|
-
|
31
|
+
rake_classes << base
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
# override task on (main), for compatibility with Rake 0.9
|
37
|
-
|
37
|
+
instance_eval do
|
38
38
|
alias rake_namespace namespace
|
39
39
|
|
40
40
|
def task(*)
|
41
41
|
task = super
|
42
42
|
|
43
|
-
if klass = Thor::RakeCompat.rake_classes.last
|
43
|
+
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
|
44
44
|
non_namespaced_name = task.name.split(':').last
|
45
45
|
|
46
46
|
description = non_namespaced_name
|
47
|
-
description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ')
|
47
|
+
description << task.arg_names.map { |n| n.to_s.upcase }.join(' ')
|
48
48
|
description.strip!
|
49
49
|
|
50
50
|
klass.desc description, Rake.application.last_description || non_namespaced_name
|
@@ -58,7 +58,7 @@ self.instance_eval do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def namespace(name)
|
61
|
-
if klass = Thor::RakeCompat.rake_classes.last
|
61
|
+
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
|
62
62
|
const_name = Thor::Util.camel_case(name.to_s).to_sym
|
63
63
|
klass.const_set(const_name, Class.new(Thor))
|
64
64
|
new_klass = klass.const_get(const_name)
|
@@ -69,4 +69,3 @@ self.instance_eval do
|
|
69
69
|
Thor::RakeCompat.rake_classes.pop
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
@@ -8,8 +8,8 @@ require 'yaml'
|
|
8
8
|
require 'digest/md5'
|
9
9
|
require 'pathname'
|
10
10
|
|
11
|
-
class Thor::Runner < Thor #:nodoc:
|
12
|
-
map
|
11
|
+
class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
12
|
+
map '-T' => :list, '-i' => :install, '-u' => :update, '-v' => :version
|
13
13
|
|
14
14
|
# Override Thor#help so it can give information about any class and any method.
|
15
15
|
#
|
@@ -18,7 +18,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
18
18
|
initialize_thorfiles(meth)
|
19
19
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
20
20
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
21
|
-
klass.start([
|
21
|
+
klass.start(['-h', command].compact, :shell => shell)
|
22
22
|
else
|
23
23
|
super
|
24
24
|
end
|
@@ -33,38 +33,38 @@ class Thor::Runner < Thor #:nodoc:
|
|
33
33
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
34
34
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
35
35
|
args.unshift(command) if command
|
36
|
-
klass.start(args, :shell =>
|
36
|
+
klass.start(args, :shell => shell)
|
37
37
|
end
|
38
38
|
|
39
|
-
desc
|
39
|
+
desc 'install NAME', 'Install an optionally named Thor file into your system commands'
|
40
40
|
method_options :as => :string, :relative => :boolean, :force => :boolean
|
41
|
-
def install(name)
|
41
|
+
def install(name) # rubocop:disable MethodLength
|
42
42
|
initialize_thorfiles
|
43
43
|
|
44
44
|
# If a directory name is provided as the argument, look for a 'main.thor'
|
45
45
|
# command in said directory.
|
46
46
|
begin
|
47
47
|
if File.directory?(File.expand_path(name))
|
48
|
-
base, package = File.join(name,
|
49
|
-
contents = open(base) {|input| input.read }
|
48
|
+
base, package = File.join(name, 'main.thor'), :directory
|
49
|
+
contents = open(base) { |input| input.read }
|
50
50
|
else
|
51
51
|
base, package = name, :file
|
52
|
-
contents = open(name) {|input| input.read }
|
52
|
+
contents = open(name) { |input| input.read }
|
53
53
|
end
|
54
54
|
rescue OpenURI::HTTPError
|
55
55
|
raise Error, "Error opening URI '#{name}'"
|
56
56
|
rescue Errno::ENOENT
|
57
|
-
|
57
|
+
fail Error, "Error opening file '#{name}'"
|
58
58
|
end
|
59
59
|
|
60
|
-
say
|
60
|
+
say 'Your Thorfile contains:'
|
61
61
|
say contents
|
62
62
|
|
63
|
-
unless options[
|
64
|
-
return false if no?(
|
63
|
+
unless options['force']
|
64
|
+
return false if no?('Do you wish to continue [y/N]?')
|
65
65
|
end
|
66
66
|
|
67
|
-
as = options[
|
67
|
+
as = options['as'] || begin
|
68
68
|
first_line = contents.split("\n")[0]
|
69
69
|
(match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
|
70
70
|
end
|
@@ -75,11 +75,11 @@ class Thor::Runner < Thor #:nodoc:
|
|
75
75
|
as = basename if as.empty?
|
76
76
|
end
|
77
77
|
|
78
|
-
location = if options[:relative] || name =~
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
location = if options[:relative] || name =~ %r{^https?://}
|
79
|
+
name
|
80
|
+
else
|
81
|
+
File.expand_path(name)
|
82
|
+
end
|
83
83
|
|
84
84
|
thor_yaml[as] = {
|
85
85
|
:filename => Digest::MD5.hexdigest(name + as),
|
@@ -88,11 +88,11 @@ class Thor::Runner < Thor #:nodoc:
|
|
88
88
|
}
|
89
89
|
|
90
90
|
save_yaml(thor_yaml)
|
91
|
-
say
|
91
|
+
say 'Storing thor file in your system repository'
|
92
92
|
destination = File.join(thor_root, thor_yaml[as][:filename])
|
93
93
|
|
94
94
|
if package == :file
|
95
|
-
File.open(destination,
|
95
|
+
File.open(destination, 'w') { |f| f.puts contents }
|
96
96
|
else
|
97
97
|
FileUtils.cp_r(name, destination)
|
98
98
|
end
|
@@ -100,32 +100,32 @@ class Thor::Runner < Thor #:nodoc:
|
|
100
100
|
thor_yaml[as][:filename] # Indicate success
|
101
101
|
end
|
102
102
|
|
103
|
-
desc
|
103
|
+
desc 'version', 'Show Thor version'
|
104
104
|
def version
|
105
105
|
require 'thor/version'
|
106
106
|
say "Thor #{Thor::VERSION}"
|
107
107
|
end
|
108
108
|
|
109
|
-
desc
|
109
|
+
desc 'uninstall NAME', 'Uninstall a named Thor module'
|
110
110
|
def uninstall(name)
|
111
|
-
|
111
|
+
fail Error, "Can't find module '#{name}'" unless thor_yaml[name]
|
112
112
|
say "Uninstalling #{name}."
|
113
113
|
FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}"))
|
114
114
|
|
115
115
|
thor_yaml.delete(name)
|
116
116
|
save_yaml(thor_yaml)
|
117
117
|
|
118
|
-
puts
|
118
|
+
puts 'Done.'
|
119
119
|
end
|
120
120
|
|
121
|
-
desc
|
121
|
+
desc 'update NAME', 'Update a Thor file from its original location'
|
122
122
|
def update(name)
|
123
|
-
|
123
|
+
fail Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
|
124
124
|
|
125
125
|
say "Updating '#{name}' from #{thor_yaml[name][:location]}"
|
126
126
|
|
127
127
|
old_filename = thor_yaml[name][:filename]
|
128
|
-
self.options =
|
128
|
+
self.options = options.merge('as' => name)
|
129
129
|
|
130
130
|
if File.directory? File.expand_path(name)
|
131
131
|
FileUtils.rm_rf(File.join(thor_root, old_filename))
|
@@ -143,21 +143,21 @@ class Thor::Runner < Thor #:nodoc:
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
desc
|
146
|
+
desc 'installed', 'List the installed Thor modules and commands'
|
147
147
|
method_options :internal => :boolean
|
148
148
|
def installed
|
149
149
|
initialize_thorfiles(nil, true)
|
150
|
-
display_klasses(true, options[
|
150
|
+
display_klasses(true, options['internal'])
|
151
151
|
end
|
152
152
|
|
153
|
-
desc
|
153
|
+
desc 'list [SEARCH]', 'List the available thor commands (--substring means .*SEARCH)'
|
154
154
|
method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
|
155
|
-
def list(search=
|
155
|
+
def list(search = '')
|
156
156
|
initialize_thorfiles
|
157
157
|
|
158
|
-
search = ".*#{search}" if options[
|
158
|
+
search = ".*#{search}" if options['substring']
|
159
159
|
search = /^#{search}.*/i
|
160
|
-
group = options[:group] ||
|
160
|
+
group = options[:group] || 'standard'
|
161
161
|
|
162
162
|
klasses = Thor::Base.subclasses.select do |k|
|
163
163
|
(options[:all] || k.group == group) && k.namespace =~ search
|
@@ -166,157 +166,157 @@ class Thor::Runner < Thor #:nodoc:
|
|
166
166
|
display_klasses(false, false, klasses)
|
167
167
|
end
|
168
168
|
|
169
|
-
|
169
|
+
private
|
170
170
|
|
171
|
-
|
172
|
-
|
173
|
-
|
171
|
+
def self.banner(command, all = false, subcommand = false)
|
172
|
+
'thor ' + command.formatted_usage(self, all, subcommand)
|
173
|
+
end
|
174
|
+
|
175
|
+
def thor_root
|
176
|
+
Thor::Util.thor_root
|
177
|
+
end
|
174
178
|
|
175
|
-
|
176
|
-
|
179
|
+
def thor_yaml
|
180
|
+
@thor_yaml ||= begin
|
181
|
+
yaml_file = File.join(thor_root, 'thor.yml')
|
182
|
+
yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
|
183
|
+
yaml || {}
|
177
184
|
end
|
185
|
+
end
|
178
186
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
187
|
+
# Save the yaml file. If none exists in thor root, creates one.
|
188
|
+
#
|
189
|
+
def save_yaml(yaml)
|
190
|
+
yaml_file = File.join(thor_root, 'thor.yml')
|
191
|
+
|
192
|
+
unless File.exist?(yaml_file)
|
193
|
+
FileUtils.mkdir_p(thor_root)
|
194
|
+
yaml_file = File.join(thor_root, 'thor.yml')
|
195
|
+
FileUtils.touch(yaml_file)
|
185
196
|
end
|
186
197
|
|
187
|
-
|
188
|
-
|
189
|
-
def save_yaml(yaml)
|
190
|
-
yaml_file = File.join(thor_root, "thor.yml")
|
198
|
+
File.open(yaml_file, 'w') { |f| f.puts yaml.to_yaml }
|
199
|
+
end
|
191
200
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
FileUtils.touch(yaml_file)
|
196
|
-
end
|
201
|
+
def self.exit_on_failure?
|
202
|
+
true
|
203
|
+
end
|
197
204
|
|
198
|
-
|
205
|
+
# Load the Thorfiles. If relevant_to is supplied, looks for specific files
|
206
|
+
# in the thor_root instead of loading them all.
|
207
|
+
#
|
208
|
+
# By default, it also traverses the current path until find Thor files, as
|
209
|
+
# described in thorfiles. This look up can be skipped by supplying
|
210
|
+
# skip_lookup true.
|
211
|
+
#
|
212
|
+
def initialize_thorfiles(relevant_to = nil, skip_lookup = false)
|
213
|
+
thorfiles(relevant_to, skip_lookup).each do |f|
|
214
|
+
Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
|
199
215
|
end
|
216
|
+
end
|
200
217
|
|
201
|
-
|
202
|
-
|
203
|
-
|
218
|
+
# Finds Thorfiles by traversing from your current directory down to the root
|
219
|
+
# directory of your system. If at any time we find a Thor file, we stop.
|
220
|
+
#
|
221
|
+
# We also ensure that system-wide Thorfiles are loaded first, so local
|
222
|
+
# Thorfiles can override them.
|
223
|
+
#
|
224
|
+
# ==== Example
|
225
|
+
#
|
226
|
+
# If we start at /Users/wycats/dev/thor ...
|
227
|
+
#
|
228
|
+
# 1. /Users/wycats/dev/thor
|
229
|
+
# 2. /Users/wycats/dev
|
230
|
+
# 3. /Users/wycats <-- we find a Thorfile here, so we stop
|
231
|
+
#
|
232
|
+
# Suppose we start at c:\Documents and Settings\james\dev\thor ...
|
233
|
+
#
|
234
|
+
# 1. c:\Documents and Settings\james\dev\thor
|
235
|
+
# 2. c:\Documents and Settings\james\dev
|
236
|
+
# 3. c:\Documents and Settings\james
|
237
|
+
# 4. c:\Documents and Settings
|
238
|
+
# 5. c:\ <-- no Thorfiles found!
|
239
|
+
#
|
240
|
+
def thorfiles(relevant_to = nil, skip_lookup = false)
|
241
|
+
thorfiles = []
|
204
242
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
# described in thorfiles. This look up can be skipped by supplying
|
210
|
-
# skip_lookup true.
|
211
|
-
#
|
212
|
-
def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
|
213
|
-
thorfiles(relevant_to, skip_lookup).each do |f|
|
214
|
-
Thor::Util.load_thorfile(f, nil, options[:debug]) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
|
243
|
+
unless skip_lookup
|
244
|
+
Pathname.pwd.ascend do |path|
|
245
|
+
thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
|
246
|
+
break unless thorfiles.empty?
|
215
247
|
end
|
216
248
|
end
|
217
249
|
|
218
|
-
|
219
|
-
|
220
|
-
#
|
221
|
-
# We also ensure that system-wide Thorfiles are loaded first, so local
|
222
|
-
# Thorfiles can override them.
|
223
|
-
#
|
224
|
-
# ==== Example
|
225
|
-
#
|
226
|
-
# If we start at /Users/wycats/dev/thor ...
|
227
|
-
#
|
228
|
-
# 1. /Users/wycats/dev/thor
|
229
|
-
# 2. /Users/wycats/dev
|
230
|
-
# 3. /Users/wycats <-- we find a Thorfile here, so we stop
|
231
|
-
#
|
232
|
-
# Suppose we start at c:\Documents and Settings\james\dev\thor ...
|
233
|
-
#
|
234
|
-
# 1. c:\Documents and Settings\james\dev\thor
|
235
|
-
# 2. c:\Documents and Settings\james\dev
|
236
|
-
# 3. c:\Documents and Settings\james
|
237
|
-
# 4. c:\Documents and Settings
|
238
|
-
# 5. c:\ <-- no Thorfiles found!
|
239
|
-
#
|
240
|
-
def thorfiles(relevant_to=nil, skip_lookup=false)
|
241
|
-
thorfiles = []
|
242
|
-
|
243
|
-
unless skip_lookup
|
244
|
-
Pathname.pwd.ascend do |path|
|
245
|
-
thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
|
246
|
-
break unless thorfiles.empty?
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
|
251
|
-
files += thorfiles
|
252
|
-
files -= ["#{thor_root}/thor.yml"]
|
250
|
+
files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
|
251
|
+
files += thorfiles
|
252
|
+
files -= ["#{thor_root}/thor.yml"]
|
253
253
|
|
254
|
-
|
255
|
-
|
256
|
-
end
|
254
|
+
files.map! do |file|
|
255
|
+
File.directory?(file) ? File.join(file, 'main.thor') : file
|
257
256
|
end
|
257
|
+
end
|
258
258
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
files = thor_yaml.select do |k, v|
|
267
|
-
v[:namespaces] && !(v[:namespaces] & lookup).empty?
|
268
|
-
end
|
259
|
+
# Load Thorfiles relevant to the given method. If you provide "foo:bar" it
|
260
|
+
# will load all thor files in the thor.yaml that has "foo" e "foo:bar"
|
261
|
+
# namespaces registered.
|
262
|
+
#
|
263
|
+
def thorfiles_relevant_to(meth)
|
264
|
+
lookup = [meth, meth.split(':')[0...-1].join(':')]
|
269
265
|
|
270
|
-
|
266
|
+
files = thor_yaml.select do |k, v|
|
267
|
+
v[:namespaces] && !(v[:namespaces] & lookup).empty?
|
271
268
|
end
|
272
269
|
|
273
|
-
|
274
|
-
|
275
|
-
#
|
276
|
-
def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
|
277
|
-
klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
|
270
|
+
files.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
|
271
|
+
end
|
278
272
|
|
279
|
-
|
280
|
-
|
273
|
+
# Display information about the given klasses. If with_module is given,
|
274
|
+
# it shows a table with information extracted from the yaml file.
|
275
|
+
#
|
276
|
+
def display_klasses(with_modules = false, show_internal = false, klasses = Thor::Base.subclasses)
|
277
|
+
klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
|
281
278
|
|
282
|
-
|
283
|
-
|
279
|
+
fail Error, 'No Thor commands available' if klasses.empty?
|
280
|
+
show_modules if with_modules && !thor_yaml.empty?
|
284
281
|
|
285
|
-
|
286
|
-
|
282
|
+
list = Hash.new { |h, k| h[k] = [] }
|
283
|
+
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
|
287
284
|
|
288
|
-
|
289
|
-
|
290
|
-
list["root"] = groups
|
285
|
+
# Get classes which inherit from Thor
|
286
|
+
(klasses - groups).each { |k| list[k.namespace.split(':').first] += k.printable_commands(false) }
|
291
287
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
end
|
288
|
+
# Get classes which inherit from Thor::Base
|
289
|
+
groups.map! { |k| k.printable_commands(false).first }
|
290
|
+
list['root'] = groups
|
296
291
|
|
297
|
-
|
298
|
-
|
292
|
+
# Order namespaces with default coming first
|
293
|
+
list = list.sort { |a, b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
|
294
|
+
list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
|
295
|
+
end
|
299
296
|
|
300
|
-
|
301
|
-
|
297
|
+
def display_commands(namespace, list) #:nodoc:
|
298
|
+
list.sort! { |a, b| a[0] <=> b[0] }
|
302
299
|
|
303
|
-
|
304
|
-
|
305
|
-
end
|
306
|
-
alias display_tasks display_commands
|
300
|
+
say shell.set_color(namespace, :blue, true)
|
301
|
+
say '-' * namespace.size
|
307
302
|
|
308
|
-
|
309
|
-
|
310
|
-
|
303
|
+
print_table(list, :truncate => true)
|
304
|
+
say
|
305
|
+
end
|
306
|
+
alias_method :display_tasks, :display_commands
|
311
307
|
|
312
|
-
|
313
|
-
|
308
|
+
def show_modules #:nodoc:
|
309
|
+
info = []
|
310
|
+
labels = %w[Modules Namespaces]
|
314
311
|
|
315
|
-
|
316
|
-
|
317
|
-
end
|
312
|
+
info << labels
|
313
|
+
info << ['-' * labels[0].size, '-' * labels[1].size]
|
318
314
|
|
319
|
-
|
320
|
-
|
315
|
+
thor_yaml.each do |name, hash|
|
316
|
+
info << [name, hash[:namespaces].join(', ')]
|
321
317
|
end
|
318
|
+
|
319
|
+
print_table info
|
320
|
+
say ''
|
321
|
+
end
|
322
322
|
end
|