crazy-yard 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +438 -0
  4. data/bin/ey +9 -0
  5. data/lib/engineyard.rb +9 -0
  6. data/lib/engineyard/cli.rb +816 -0
  7. data/lib/engineyard/cli/api.rb +98 -0
  8. data/lib/engineyard/cli/recipes.rb +129 -0
  9. data/lib/engineyard/cli/ui.rb +275 -0
  10. data/lib/engineyard/cli/web.rb +85 -0
  11. data/lib/engineyard/config.rb +158 -0
  12. data/lib/engineyard/deploy_config.rb +65 -0
  13. data/lib/engineyard/deploy_config/ref.rb +56 -0
  14. data/lib/engineyard/error.rb +82 -0
  15. data/lib/engineyard/eyrc.rb +59 -0
  16. data/lib/engineyard/repo.rb +105 -0
  17. data/lib/engineyard/serverside_runner.rb +159 -0
  18. data/lib/engineyard/templates.rb +6 -0
  19. data/lib/engineyard/templates/ey.yml.erb +196 -0
  20. data/lib/engineyard/templates/ey_yml.rb +119 -0
  21. data/lib/engineyard/thor.rb +215 -0
  22. data/lib/engineyard/version.rb +4 -0
  23. data/lib/vendor/thor/Gemfile +15 -0
  24. data/lib/vendor/thor/LICENSE.md +20 -0
  25. data/lib/vendor/thor/README.md +35 -0
  26. data/lib/vendor/thor/lib/thor.rb +473 -0
  27. data/lib/vendor/thor/lib/thor/actions.rb +318 -0
  28. data/lib/vendor/thor/lib/thor/actions/create_file.rb +105 -0
  29. data/lib/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  30. data/lib/vendor/thor/lib/thor/actions/directory.rb +119 -0
  31. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +137 -0
  32. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +314 -0
  33. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  34. data/lib/vendor/thor/lib/thor/base.rb +652 -0
  35. data/lib/vendor/thor/lib/thor/command.rb +136 -0
  36. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  37. data/lib/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  38. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  39. data/lib/vendor/thor/lib/thor/error.rb +28 -0
  40. data/lib/vendor/thor/lib/thor/group.rb +282 -0
  41. data/lib/vendor/thor/lib/thor/invocation.rb +172 -0
  42. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  43. data/lib/vendor/thor/lib/thor/parser/argument.rb +74 -0
  44. data/lib/vendor/thor/lib/thor/parser/arguments.rb +171 -0
  45. data/lib/vendor/thor/lib/thor/parser/option.rb +121 -0
  46. data/lib/vendor/thor/lib/thor/parser/options.rb +218 -0
  47. data/lib/vendor/thor/lib/thor/rake_compat.rb +72 -0
  48. data/lib/vendor/thor/lib/thor/runner.rb +322 -0
  49. data/lib/vendor/thor/lib/thor/shell.rb +88 -0
  50. data/lib/vendor/thor/lib/thor/shell/basic.rb +393 -0
  51. data/lib/vendor/thor/lib/thor/shell/color.rb +148 -0
  52. data/lib/vendor/thor/lib/thor/shell/html.rb +127 -0
  53. data/lib/vendor/thor/lib/thor/util.rb +270 -0
  54. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  55. data/lib/vendor/thor/thor.gemspec +24 -0
  56. data/spec/engineyard/cli/api_spec.rb +50 -0
  57. data/spec/engineyard/cli_spec.rb +28 -0
  58. data/spec/engineyard/config_spec.rb +61 -0
  59. data/spec/engineyard/deploy_config_spec.rb +194 -0
  60. data/spec/engineyard/eyrc_spec.rb +76 -0
  61. data/spec/engineyard/repo_spec.rb +83 -0
  62. data/spec/engineyard_spec.rb +7 -0
  63. data/spec/ey/console_spec.rb +57 -0
  64. data/spec/ey/deploy_spec.rb +435 -0
  65. data/spec/ey/ey_spec.rb +23 -0
  66. data/spec/ey/init_spec.rb +123 -0
  67. data/spec/ey/list_environments_spec.rb +120 -0
  68. data/spec/ey/login_spec.rb +33 -0
  69. data/spec/ey/logout_spec.rb +24 -0
  70. data/spec/ey/logs_spec.rb +36 -0
  71. data/spec/ey/rebuild_spec.rb +18 -0
  72. data/spec/ey/recipes/apply_spec.rb +29 -0
  73. data/spec/ey/recipes/download_spec.rb +43 -0
  74. data/spec/ey/recipes/upload_spec.rb +99 -0
  75. data/spec/ey/rollback_spec.rb +73 -0
  76. data/spec/ey/scp_spec.rb +176 -0
  77. data/spec/ey/servers_spec.rb +209 -0
  78. data/spec/ey/ssh_spec.rb +273 -0
  79. data/spec/ey/status_spec.rb +45 -0
  80. data/spec/ey/timeout_deploy_spec.rb +18 -0
  81. data/spec/ey/web/disable_spec.rb +21 -0
  82. data/spec/ey/web/enable_spec.rb +26 -0
  83. data/spec/ey/web/restart_spec.rb +21 -0
  84. data/spec/ey/whoami_spec.rb +30 -0
  85. data/spec/spec_helper.rb +84 -0
  86. data/spec/support/bundled_ey +7 -0
  87. data/spec/support/fixture_recipes.tgz +0 -0
  88. data/spec/support/git_repos.rb +115 -0
  89. data/spec/support/helpers.rb +330 -0
  90. data/spec/support/matchers.rb +16 -0
  91. data/spec/support/ruby_ext.rb +13 -0
  92. data/spec/support/shared_behavior.rb +278 -0
  93. metadata +411 -0
@@ -0,0 +1,109 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Injects the given content into a file. Different from gsub_file, this
7
+ # method is reversible.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: Relative path to the destination root
11
+ # data<String>:: Data to add to the file. Can be given as a block.
12
+ # config<Hash>:: give :verbose => false to not log the status and the flag
13
+ # for injection (:after or :before) or :force => true for
14
+ # insert two or more times the same content.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
19
+ #
20
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
21
+ # gems = ask "Which gems would you like to add?"
22
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
23
+ # end
24
+ #
25
+ def insert_into_file(destination, *args, &block)
26
+ if block_given?
27
+ data, config = block, args.shift
28
+ else
29
+ data, config = args.shift, args.shift
30
+ end
31
+ action InjectIntoFile.new(self, destination, data, config)
32
+ end
33
+ alias_method :inject_into_file, :insert_into_file
34
+
35
+ class InjectIntoFile < EmptyDirectory #:nodoc:
36
+ attr_reader :replacement, :flag, :behavior
37
+
38
+ def initialize(base, destination, data, config)
39
+ super(base, destination, { :verbose => true }.merge(config))
40
+
41
+ @behavior, @flag = if @config.key?(:after)
42
+ [:after, @config.delete(:after)]
43
+ else
44
+ [:before, @config.delete(:before)]
45
+ end
46
+
47
+ @replacement = data.is_a?(Proc) ? data.call : data
48
+ @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
49
+ end
50
+
51
+ def invoke!
52
+ say_status :invoke
53
+
54
+ content = if @behavior == :after
55
+ '\0' + replacement
56
+ else
57
+ replacement + '\0'
58
+ end
59
+
60
+ replace!(/#{flag}/, content, config[:force])
61
+ end
62
+
63
+ def revoke!
64
+ say_status :revoke
65
+
66
+ regexp = if @behavior == :after
67
+ content = '\1\2'
68
+ /(#{flag})(.*)(#{Regexp.escape(replacement)})/m
69
+ else
70
+ content = '\2\3'
71
+ /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
72
+ end
73
+
74
+ replace!(regexp, content, true)
75
+ end
76
+
77
+ protected
78
+
79
+ def say_status(behavior)
80
+ status = if behavior == :invoke
81
+ if flag == /\A/
82
+ :prepend
83
+ elsif flag == /\z/
84
+ :append
85
+ else
86
+ :insert
87
+ end
88
+ else
89
+ :subtract
90
+ end
91
+
92
+ super(status, config[:verbose])
93
+ end
94
+
95
+ # Adds the content to the file.
96
+ #
97
+ def replace!(regexp, string, force)
98
+ unless base.options[:pretend]
99
+ content = File.binread(destination)
100
+ if force || !content.include?(replacement)
101
+ content.gsub!(regexp, string)
102
+ File.open(destination, 'wb') { |file| file.write(content) }
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,652 @@
1
+ require 'thor/command'
2
+ require 'thor/core_ext/hash_with_indifferent_access'
3
+ require 'thor/core_ext/ordered_hash'
4
+ require 'thor/error'
5
+ require 'thor/invocation'
6
+ require 'thor/parser'
7
+ require 'thor/shell'
8
+ require 'thor/util'
9
+
10
+ class Thor
11
+ autoload :Actions, 'thor/actions'
12
+ autoload :RakeCompat, 'thor/rake_compat'
13
+ autoload :Group, 'thor/group'
14
+
15
+ # Shortcuts for help.
16
+ HELP_MAPPINGS = %w(-h -? --help -D)
17
+
18
+ # Thor methods that should not be overwritten by the user.
19
+ THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
20
+ action add_file create_file in_root inside run run_ruby_script)
21
+
22
+ module Base
23
+ attr_accessor :options, :parent_options, :args
24
+
25
+ # It receives arguments in an Array and two hashes, one for options and
26
+ # other for configuration.
27
+ #
28
+ # Notice that it does not check if all required arguments were supplied.
29
+ # It should be done by the parser.
30
+ #
31
+ # ==== Parameters
32
+ # args<Array[Object]>:: An array of objects. The objects are applied to their
33
+ # respective accessors declared with <tt>argument</tt>.
34
+ #
35
+ # options<Hash>:: An options hash that will be available as self.options.
36
+ # The hash given is converted to a hash with indifferent
37
+ # access, magic predicates (options.skip?) and then frozen.
38
+ #
39
+ # config<Hash>:: Configuration for this Thor class.
40
+ #
41
+ def initialize(args=[], options={}, config={})
42
+ parse_options = self.class.class_options
43
+
44
+ # The start method splits inbound arguments at the first argument
45
+ # that looks like an option (starts with - or --). It then calls
46
+ # new, passing in the two halves of the arguments Array as the
47
+ # first two parameters.
48
+
49
+ if options.is_a?(Array)
50
+ command_options = config.delete(:command_options) # hook for start
51
+ parse_options = parse_options.merge(command_options) if command_options
52
+ array_options, hash_options = options, {}
53
+ else
54
+ # Handle the case where the class was explicitly instantiated
55
+ # with pre-parsed options.
56
+ array_options, hash_options = [], options
57
+ end
58
+
59
+ # Let Thor::Options parse the options first, so it can remove
60
+ # declared options from the array. This will leave us with
61
+ # a list of arguments that weren't declared.
62
+ stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
63
+ opts = Thor::Options.new(parse_options, hash_options, stop_on_unknown)
64
+ self.options = opts.parse(array_options)
65
+ self.options = config[:class_options].merge(self.options) if config[:class_options]
66
+
67
+ # If unknown options are disallowed, make sure that none of the
68
+ # remaining arguments looks like an option.
69
+ opts.check_unknown! if self.class.check_unknown_options?(config)
70
+
71
+ # Add the remaining arguments from the options parser to the
72
+ # arguments passed in to initialize. Then remove any positional
73
+ # arguments declared using #argument (this is primarily used
74
+ # by Thor::Group). Tis will leave us with the remaining
75
+ # positional arguments.
76
+ to_parse = args
77
+ to_parse += opts.remaining unless self.class.strict_args_position?(config)
78
+
79
+ thor_args = Thor::Arguments.new(self.class.arguments)
80
+ thor_args.parse(to_parse).each { |k,v| __send__("#{k}=", v) }
81
+ @args = thor_args.remaining
82
+ end
83
+
84
+ class << self
85
+ def included(base) #:nodoc:
86
+ base.send :extend, ClassMethods
87
+ base.send :include, Invocation
88
+ base.send :include, Shell
89
+ end
90
+
91
+ # Returns the classes that inherits from Thor or Thor::Group.
92
+ #
93
+ # ==== Returns
94
+ # Array[Class]
95
+ #
96
+ def subclasses
97
+ @subclasses ||= []
98
+ end
99
+
100
+ # Returns the files where the subclasses are kept.
101
+ #
102
+ # ==== Returns
103
+ # Hash[path<String> => Class]
104
+ #
105
+ def subclass_files
106
+ @subclass_files ||= Hash.new{ |h,k| h[k] = [] }
107
+ end
108
+
109
+ # Whenever a class inherits from Thor or Thor::Group, we should track the
110
+ # class and the file on Thor::Base. This is the method responsable for it.
111
+ #
112
+ def register_klass_file(klass) #:nodoc:
113
+ file = caller[1].match(/(.*):\d+/)[1]
114
+ Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass)
115
+
116
+ file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
117
+ file_subclasses << klass unless file_subclasses.include?(klass)
118
+ end
119
+ end
120
+
121
+ module ClassMethods
122
+ def attr_reader(*) #:nodoc:
123
+ no_commands { super }
124
+ end
125
+
126
+ def attr_writer(*) #:nodoc:
127
+ no_commands { super }
128
+ end
129
+
130
+ def attr_accessor(*) #:nodoc:
131
+ no_commands { super }
132
+ end
133
+
134
+ # If you want to raise an error for unknown options, call check_unknown_options!
135
+ # This is disabled by default to allow dynamic invocations.
136
+ def check_unknown_options!
137
+ @check_unknown_options = true
138
+ end
139
+
140
+ def check_unknown_options #:nodoc:
141
+ @check_unknown_options ||= from_superclass(:check_unknown_options, false)
142
+ end
143
+
144
+ def check_unknown_options?(config) #:nodoc:
145
+ !!check_unknown_options
146
+ end
147
+
148
+ # If true, option parsing is suspended as soon as an unknown option or a
149
+ # regular argument is encountered. All remaining arguments are passed to
150
+ # the command as regular arguments.
151
+ def stop_on_unknown_option?(command_name) #:nodoc:
152
+ false
153
+ end
154
+
155
+ # If you want only strict string args (useful when cascading thor classes),
156
+ # call strict_args_position! This is disabled by default to allow dynamic
157
+ # invocations.
158
+ def strict_args_position!
159
+ @strict_args_position = true
160
+ end
161
+
162
+ def strict_args_position #:nodoc:
163
+ @strict_args_position ||= from_superclass(:strict_args_position, false)
164
+ end
165
+
166
+ def strict_args_position?(config) #:nodoc:
167
+ !!strict_args_position
168
+ end
169
+
170
+ # Adds an argument to the class and creates an attr_accessor for it.
171
+ #
172
+ # Arguments are different from options in several aspects. The first one
173
+ # is how they are parsed from the command line, arguments are retrieved
174
+ # from position:
175
+ #
176
+ # thor command NAME
177
+ #
178
+ # Instead of:
179
+ #
180
+ # thor command --name=NAME
181
+ #
182
+ # Besides, arguments are used inside your code as an accessor (self.argument),
183
+ # while options are all kept in a hash (self.options).
184
+ #
185
+ # Finally, arguments cannot have type :default or :boolean but can be
186
+ # optional (supplying :optional => :true or :required => false), although
187
+ # you cannot have a required argument after a non-required argument. If you
188
+ # try it, an error is raised.
189
+ #
190
+ # ==== Parameters
191
+ # name<Symbol>:: The name of the argument.
192
+ # options<Hash>:: Described below.
193
+ #
194
+ # ==== Options
195
+ # :desc - Description for the argument.
196
+ # :required - If the argument is required or not.
197
+ # :optional - If the argument is optional or not.
198
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric.
199
+ # :default - Default value for this argument. It cannot be required and have default values.
200
+ # :banner - String to show on usage notes.
201
+ #
202
+ # ==== Errors
203
+ # ArgumentError:: Raised if you supply a required argument after a non required one.
204
+ #
205
+ def argument(name, options={})
206
+ is_thor_reserved_word?(name, :argument)
207
+ no_commands { attr_accessor name }
208
+
209
+ required = if options.key?(:optional)
210
+ !options[:optional]
211
+ elsif options.key?(:required)
212
+ options[:required]
213
+ else
214
+ options[:default].nil?
215
+ end
216
+
217
+ remove_argument name
218
+
219
+ arguments.each do |argument|
220
+ next if argument.required?
221
+ raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
222
+ "the non-required argument #{argument.human_name.inspect}."
223
+ end if required
224
+
225
+ options[:required] = required
226
+
227
+ arguments << Thor::Argument.new(name, options)
228
+ end
229
+
230
+ # Returns this class arguments, looking up in the ancestors chain.
231
+ #
232
+ # ==== Returns
233
+ # Array[Thor::Argument]
234
+ #
235
+ def arguments
236
+ @arguments ||= from_superclass(:arguments, [])
237
+ end
238
+
239
+ # Adds a bunch of options to the set of class options.
240
+ #
241
+ # class_options :foo => false, :bar => :required, :baz => :string
242
+ #
243
+ # If you prefer more detailed declaration, check class_option.
244
+ #
245
+ # ==== Parameters
246
+ # Hash[Symbol => Object]
247
+ #
248
+ def class_options(options=nil)
249
+ @class_options ||= from_superclass(:class_options, {})
250
+ build_options(options, @class_options) if options
251
+ @class_options
252
+ end
253
+
254
+ # Adds an option to the set of class options
255
+ #
256
+ # ==== Parameters
257
+ # name<Symbol>:: The name of the argument.
258
+ # options<Hash>:: Described below.
259
+ #
260
+ # ==== Options
261
+ # :desc:: -- Description for the argument.
262
+ # :required:: -- If the argument is required or not.
263
+ # :default:: -- Default value for this argument.
264
+ # :group:: -- The group for this options. Use by class options to output options in different levels.
265
+ # :aliases:: -- Aliases for this option. <b>Note:</b> Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead.
266
+ # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
267
+ # :banner:: -- String to show on usage notes.
268
+ # :hide:: -- If you want to hide this option from the help.
269
+ #
270
+ def class_option(name, options={})
271
+ build_option(name, options, class_options)
272
+ end
273
+
274
+ # Removes a previous defined argument. If :undefine is given, undefine
275
+ # accessors as well.
276
+ #
277
+ # ==== Parameters
278
+ # names<Array>:: Arguments to be removed
279
+ #
280
+ # ==== Examples
281
+ #
282
+ # remove_argument :foo
283
+ # remove_argument :foo, :bar, :baz, :undefine => true
284
+ #
285
+ def remove_argument(*names)
286
+ options = names.last.is_a?(Hash) ? names.pop : {}
287
+
288
+ names.each do |name|
289
+ arguments.delete_if { |a| a.name == name.to_s }
290
+ undef_method name, "#{name}=" if options[:undefine]
291
+ end
292
+ end
293
+
294
+ # Removes a previous defined class option.
295
+ #
296
+ # ==== Parameters
297
+ # names<Array>:: Class options to be removed
298
+ #
299
+ # ==== Examples
300
+ #
301
+ # remove_class_option :foo
302
+ # remove_class_option :foo, :bar, :baz
303
+ #
304
+ def remove_class_option(*names)
305
+ names.each do |name|
306
+ class_options.delete(name)
307
+ end
308
+ end
309
+
310
+ # Defines the group. This is used when thor list is invoked so you can specify
311
+ # that only commands from a pre-defined group will be shown. Defaults to standard.
312
+ #
313
+ # ==== Parameters
314
+ # name<String|Symbol>
315
+ #
316
+ def group(name=nil)
317
+ @group = case name
318
+ when nil
319
+ @group || from_superclass(:group, 'standard')
320
+ else
321
+ name.to_s
322
+ end
323
+ end
324
+
325
+ # Returns the commands for this Thor class.
326
+ #
327
+ # ==== Returns
328
+ # OrderedHash:: An ordered hash with commands names as keys and Thor::Command
329
+ # objects as values.
330
+ #
331
+ def commands
332
+ @commands ||= Thor::CoreExt::OrderedHash.new
333
+ end
334
+ alias tasks commands
335
+
336
+ # Returns the commands for this Thor class and all subclasses.
337
+ #
338
+ # ==== Returns
339
+ # OrderedHash:: An ordered hash with commands names as keys and Thor::Command
340
+ # objects as values.
341
+ #
342
+ def all_commands
343
+ @all_commands ||= from_superclass(:all_commands, Thor::CoreExt::OrderedHash.new)
344
+ @all_commands.merge(commands)
345
+ end
346
+ alias all_tasks all_commands
347
+
348
+ # Removes a given command from this Thor class. This is usually done if you
349
+ # are inheriting from another class and don't want it to be available
350
+ # anymore.
351
+ #
352
+ # By default it only remove the mapping to the command. But you can supply
353
+ # :undefine => true to undefine the method from the class as well.
354
+ #
355
+ # ==== Parameters
356
+ # name<Symbol|String>:: The name of the command to be removed
357
+ # options<Hash>:: You can give :undefine => true if you want commands the method
358
+ # to be undefined from the class as well.
359
+ #
360
+ def remove_command(*names)
361
+ options = names.last.is_a?(Hash) ? names.pop : {}
362
+
363
+ names.each do |name|
364
+ commands.delete(name.to_s)
365
+ all_commands.delete(name.to_s)
366
+ undef_method name if options[:undefine]
367
+ end
368
+ end
369
+ alias remove_task remove_command
370
+
371
+ # All methods defined inside the given block are not added as commands.
372
+ #
373
+ # So you can do:
374
+ #
375
+ # class MyScript < Thor
376
+ # no_commands do
377
+ # def this_is_not_a_command
378
+ # end
379
+ # end
380
+ # end
381
+ #
382
+ # You can also add the method and remove it from the command list:
383
+ #
384
+ # class MyScript < Thor
385
+ # def this_is_not_a_command
386
+ # end
387
+ # remove_command :this_is_not_a_command
388
+ # end
389
+ #
390
+ def no_commands
391
+ @no_commands = true
392
+ yield
393
+ ensure
394
+ @no_commands = false
395
+ end
396
+ alias no_tasks no_commands
397
+
398
+ # Sets the namespace for the Thor or Thor::Group class. By default the
399
+ # namespace is retrieved from the class name. If your Thor class is named
400
+ # Scripts::MyScript, the help method, for example, will be called as:
401
+ #
402
+ # thor scripts:my_script -h
403
+ #
404
+ # If you change the namespace:
405
+ #
406
+ # namespace :my_scripts
407
+ #
408
+ # You change how your commands are invoked:
409
+ #
410
+ # thor my_scripts -h
411
+ #
412
+ # Finally, if you change your namespace to default:
413
+ #
414
+ # namespace :default
415
+ #
416
+ # Your commands can be invoked with a shortcut. Instead of:
417
+ #
418
+ # thor :my_command
419
+ #
420
+ def namespace(name=nil)
421
+ @namespace = case name
422
+ when nil
423
+ @namespace || Thor::Util.namespace_from_thor_class(self)
424
+ else
425
+ @namespace = name.to_s
426
+ end
427
+ end
428
+
429
+ # Parses the command and options from the given args, instantiate the class
430
+ # and invoke the command. This method is used when the arguments must be parsed
431
+ # from an array. If you are inside Ruby and want to use a Thor class, you
432
+ # can simply initialize it:
433
+ #
434
+ # script = MyScript.new(args, options, config)
435
+ # script.invoke(:command, first_arg, second_arg, third_arg)
436
+ #
437
+ def start(given_args=ARGV, config={})
438
+ config[:shell] ||= Thor::Base.shell.new
439
+ dispatch(nil, given_args.dup, nil, config)
440
+ rescue Thor::Error => e
441
+ ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
442
+ exit(1) if exit_on_failure?
443
+ rescue Errno::EPIPE
444
+ # This happens if a thor command is piped to something like `head`,
445
+ # which closes the pipe when it's done reading. This will also
446
+ # mean that if the pipe is closed, further unnecessary
447
+ # computation will not occur.
448
+ exit(0)
449
+ end
450
+
451
+ # Allows to use private methods from parent in child classes as commands.
452
+ #
453
+ # ==== Parameters
454
+ # names<Array>:: Method names to be used as commands
455
+ #
456
+ # ==== Examples
457
+ #
458
+ # public_command :foo
459
+ # public_command :foo, :bar, :baz
460
+ #
461
+ def public_command(*names)
462
+ names.each do |name|
463
+ class_eval "def #{name}(*); super end"
464
+ end
465
+ end
466
+ alias public_task public_command
467
+
468
+ def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
469
+ if has_namespace
470
+ raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace."
471
+ else
472
+ raise UndefinedCommandError, "Could not find command #{command.inspect}."
473
+ end
474
+ end
475
+ alias handle_no_task_error handle_no_command_error
476
+
477
+ def handle_argument_error(command, error, args, arity) #:nodoc:
478
+ msg = "ERROR: #{basename} #{command.name} was called with "
479
+ msg << 'no arguments' if args.empty?
480
+ msg << 'arguments ' << args.inspect if !args.empty?
481
+ msg << "\nUsage: #{self.banner(command).inspect}."
482
+ raise InvocationError, msg
483
+ end
484
+
485
+ protected
486
+
487
+ # Prints the class options per group. If an option does not belong to
488
+ # any group, it's printed as Class option.
489
+ #
490
+ def class_options_help(shell, groups={}) #:nodoc:
491
+ # Group options by group
492
+ class_options.each do |_, value|
493
+ groups[value.group] ||= []
494
+ groups[value.group] << value
495
+ end
496
+
497
+ # Deal with default group
498
+ global_options = groups.delete(nil) || []
499
+ print_options(shell, global_options)
500
+
501
+ # Print all others
502
+ groups.each do |group_name, options|
503
+ print_options(shell, options, group_name)
504
+ end
505
+ end
506
+
507
+ # Receives a set of options and print them.
508
+ def print_options(shell, options, group_name=nil)
509
+ return if options.empty?
510
+
511
+ list = []
512
+ padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
513
+
514
+ options.each do |option|
515
+ unless option.hide
516
+ item = [ option.usage(padding) ]
517
+ item.push(option.description ? "# #{option.description}" : "")
518
+
519
+ list << item
520
+ list << [ "", "# Default: #{option.default}" ] if option.show_default?
521
+ list << [ "", "# Possible values: #{option.enum.join(', ')}" ] if option.enum
522
+ end
523
+ end
524
+
525
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
526
+ shell.print_table(list, :indent => 2)
527
+ shell.say ""
528
+ end
529
+
530
+ # Raises an error if the word given is a Thor reserved word.
531
+ def is_thor_reserved_word?(word, type) #:nodoc:
532
+ return false unless THOR_RESERVED_WORDS.include?(word.to_s)
533
+ raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
534
+ end
535
+
536
+ # Build an option and adds it to the given scope.
537
+ #
538
+ # ==== Parameters
539
+ # name<Symbol>:: The name of the argument.
540
+ # options<Hash>:: Described in both class_option and method_option.
541
+ # scope<Hash>:: Options hash that is being built up
542
+ def build_option(name, options, scope) #:nodoc:
543
+ scope[name] = Thor::Option.new(name, options)
544
+ end
545
+
546
+ # Receives a hash of options, parse them and add to the scope. This is a
547
+ # fast way to set a bunch of options:
548
+ #
549
+ # build_options :foo => true, :bar => :required, :baz => :string
550
+ #
551
+ # ==== Parameters
552
+ # Hash[Symbol => Object]
553
+ def build_options(options, scope) #:nodoc:
554
+ options.each do |key, value|
555
+ scope[key] = Thor::Option.parse(key, value)
556
+ end
557
+ end
558
+
559
+ # Finds a command with the given name. If the command belongs to the current
560
+ # class, just return it, otherwise dup it and add the fresh copy to the
561
+ # current command hash.
562
+ def find_and_refresh_command(name) #:nodoc:
563
+ command = if command = commands[name.to_s]
564
+ command
565
+ elsif command = all_commands[name.to_s]
566
+ commands[name.to_s] = command.clone
567
+ else
568
+ raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
569
+ end
570
+ end
571
+ alias find_and_refresh_task find_and_refresh_command
572
+
573
+ # Everytime someone inherits from a Thor class, register the klass
574
+ # and file into baseclass.
575
+ def inherited(klass)
576
+ Thor::Base.register_klass_file(klass)
577
+ klass.instance_variable_set(:@no_commands, false)
578
+ end
579
+
580
+ # Fire this callback whenever a method is added. Added methods are
581
+ # tracked as commands by invoking the create_command method.
582
+ def method_added(meth)
583
+ meth = meth.to_s
584
+
585
+ if meth == "initialize"
586
+ initialize_added
587
+ return
588
+ end
589
+
590
+ # Return if it's not a public instance method
591
+ return unless public_method_defined?(meth.to_sym)
592
+
593
+ return if @no_commands || !create_command(meth)
594
+
595
+ is_thor_reserved_word?(meth, :command)
596
+ Thor::Base.register_klass_file(self)
597
+ end
598
+
599
+ # Retrieves a value from superclass. If it reaches the baseclass,
600
+ # returns default.
601
+ def from_superclass(method, default=nil)
602
+ if self == baseclass || !superclass.respond_to?(method, true)
603
+ default
604
+ else
605
+ value = superclass.send(method)
606
+
607
+ if value
608
+ if value.is_a?(TrueClass) || value.is_a?(Symbol)
609
+ value
610
+ else
611
+ value.dup
612
+ end
613
+ end
614
+ end
615
+ end
616
+
617
+ # A flag that makes the process exit with status 1 if any error happens.
618
+ def exit_on_failure?
619
+ false
620
+ end
621
+
622
+ #
623
+ # The basename of the program invoking the thor class.
624
+ #
625
+ def basename
626
+ File.basename($0).split(' ').first
627
+ end
628
+
629
+ # SIGNATURE: Sets the baseclass. This is where the superclass lookup
630
+ # finishes.
631
+ def baseclass #:nodoc:
632
+ end
633
+
634
+ # SIGNATURE: Creates a new command if valid_command? is true. This method is
635
+ # called when a new method is added to the class.
636
+ def create_command(meth) #:nodoc:
637
+ end
638
+ alias create_task create_command
639
+
640
+ # SIGNATURE: Defines behavior when the initialize method is added to the
641
+ # class.
642
+ def initialize_added #:nodoc:
643
+ end
644
+
645
+ # SIGNATURE: The hook invoked by start.
646
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
647
+ raise NotImplementedError
648
+ end
649
+
650
+ end
651
+ end
652
+ end