engineyard 1.0.0 → 1.0.1

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.
Files changed (34) hide show
  1. data/lib/engineyard/cli.rb +11 -2
  2. data/lib/engineyard/model/environment.rb +36 -3
  3. data/lib/engineyard/model/instance.rb +1 -1
  4. data/lib/engineyard/thor.rb +50 -68
  5. data/lib/engineyard/version.rb +1 -1
  6. data/spec/ey/deploy_spec.rb +66 -0
  7. metadata +23 -36
  8. data/lib/engineyard/vendor/thor.rb +0 -270
  9. data/lib/engineyard/vendor/thor/actions.rb +0 -297
  10. data/lib/engineyard/vendor/thor/actions/create_file.rb +0 -105
  11. data/lib/engineyard/vendor/thor/actions/directory.rb +0 -93
  12. data/lib/engineyard/vendor/thor/actions/empty_directory.rb +0 -134
  13. data/lib/engineyard/vendor/thor/actions/file_manipulation.rb +0 -229
  14. data/lib/engineyard/vendor/thor/actions/inject_into_file.rb +0 -104
  15. data/lib/engineyard/vendor/thor/base.rb +0 -540
  16. data/lib/engineyard/vendor/thor/core_ext/file_binary_read.rb +0 -9
  17. data/lib/engineyard/vendor/thor/core_ext/hash_with_indifferent_access.rb +0 -75
  18. data/lib/engineyard/vendor/thor/core_ext/ordered_hash.rb +0 -100
  19. data/lib/engineyard/vendor/thor/error.rb +0 -30
  20. data/lib/engineyard/vendor/thor/group.rb +0 -271
  21. data/lib/engineyard/vendor/thor/invocation.rb +0 -180
  22. data/lib/engineyard/vendor/thor/parser.rb +0 -4
  23. data/lib/engineyard/vendor/thor/parser/argument.rb +0 -67
  24. data/lib/engineyard/vendor/thor/parser/arguments.rb +0 -161
  25. data/lib/engineyard/vendor/thor/parser/option.rb +0 -128
  26. data/lib/engineyard/vendor/thor/parser/options.rb +0 -164
  27. data/lib/engineyard/vendor/thor/rake_compat.rb +0 -66
  28. data/lib/engineyard/vendor/thor/runner.rb +0 -314
  29. data/lib/engineyard/vendor/thor/shell.rb +0 -83
  30. data/lib/engineyard/vendor/thor/shell/basic.rb +0 -268
  31. data/lib/engineyard/vendor/thor/shell/color.rb +0 -108
  32. data/lib/engineyard/vendor/thor/task.rb +0 -102
  33. data/lib/engineyard/vendor/thor/util.rb +0 -229
  34. data/lib/engineyard/vendor/thor/version.rb +0 -3
@@ -34,7 +34,7 @@ module EY
34
34
  method_option :ignore_bad_master, :type => :boolean,
35
35
  :desc => "Force a deploy even if the master is in a bad state"
36
36
  method_option :migrate, :type => :string, :aliases => %w(-m),
37
- :default => 'rake db:migrate',
37
+ :lazy_default => true,
38
38
  :desc => "Run migrations via [MIGRATE], defaults to 'rake db:migrate'; use --no-migrate to avoid running migrations"
39
39
  method_option :environment, :type => :string, :aliases => %w(-e),
40
40
  :desc => "Environment in which to deploy this application"
@@ -63,7 +63,16 @@ module EY
63
63
 
64
64
  EY.ui.info "Beginning deploy for '#{app.name}' in '#{environment.name}' on server..."
65
65
 
66
- if environment.deploy(app, deploy_ref, options[:migrate], options[:verbose])
66
+ # missing means do what the yaml file says
67
+ # nil means don't do it
68
+ # true (the lazy default) means do it with the custom command
69
+ # a string means do it with this specific command
70
+
71
+ deploy_options = {}
72
+ deploy_options['migrate'] = options['migrate'] if options.has_key?('migrate')
73
+ deploy_options['verbose'] = options['verbose'] if options.has_key?('verbose')
74
+
75
+ if environment.deploy(app, deploy_ref, deploy_options)
67
76
  EY.ui.info "Deploy complete"
68
77
  else
69
78
  raise EY::Error, "Deploy failed"
@@ -35,8 +35,41 @@ module EY
35
35
  app_master!.ensure_eydeploy_present(&blk)
36
36
  end
37
37
 
38
- def deploy(app, ref, migration_command=nil, verbose=false)
39
- app_master!.deploy(app, ref, migration_command, config, verbose)
38
+ def deploy(app, ref, deploy_options={})
39
+ # regarding deploy_options['migrate']:
40
+ #
41
+ # missing means migrate how the yaml file says to
42
+ # nil means don't migrate
43
+ # true means migrate w/custom command (if present) or default
44
+ # a string means migrate with this specific command
45
+
46
+ default_migration_command = config['migration_command'] || 'rake db:migrate'
47
+
48
+ migration_from_config = if config.has_key?('migrate')
49
+ if config['migrate']
50
+ default_migration_command
51
+ else
52
+ nil
53
+ end
54
+ else
55
+ default_migration_command
56
+ end
57
+
58
+ migration_from_command_line = if deploy_options['migrate'].nil?
59
+ nil
60
+ elsif deploy_options['migrate'].respond_to?(:to_str)
61
+ deploy_options['migrate'].to_str
62
+ else
63
+ default_migration_command
64
+ end
65
+
66
+ cmd = if deploy_options.has_key?('migrate')
67
+ migration_from_command_line
68
+ else
69
+ migration_from_config
70
+ end
71
+
72
+ app_master!.deploy(app, ref, cmd, config, deploy_options['verbose'])
40
73
  end
41
74
 
42
75
  def rollback(app, verbose=false)
@@ -107,7 +140,7 @@ module EY
107
140
  end
108
141
 
109
142
  def configuration
110
- EY.config.environments[self.name]
143
+ EY.config.environments[self.name] || {}
111
144
  end
112
145
  alias_method :config, :configuration
113
146
 
@@ -3,7 +3,7 @@ require 'escape'
3
3
  module EY
4
4
  module Model
5
5
  class Instance < ApiStruct.new(:id, :role, :name, :status, :amazon_id, :public_hostname, :environment)
6
- EYDEPLOY_VERSION = ENV["EY_DEPLOY_VERSION"] || "1.0.0"
6
+ EYDEPLOY_VERSION = ENV["EY_DEPLOY_VERSION"] || "1.0.1"
7
7
  EXIT_STATUS = Hash.new { |h,k| raise EY::Error, "ey-deploy version checker exited with unknown status code #{k}" }
8
8
  EXIT_STATUS.merge!({
9
9
  255 => :ssh_failed,
@@ -1,74 +1,8 @@
1
- $LOAD_PATH.unshift File.expand_path("../vendor", __FILE__)
2
1
  require 'thor'
3
2
 
4
3
  module EY
5
- class Thor < ::Thor
6
- def self.start(original_args=ARGV, config={})
7
- @@original_args = original_args
8
- super
9
- end
10
-
11
- no_tasks do
12
- def self.subcommands
13
- @@subcommands ||= {}
14
- end
15
-
16
- def self.subcommand(subcommand, subcommand_class)
17
- subcommand = subcommand.to_s
18
- subcommands[subcommand] = subcommand_class
19
- subcommand_class.subcommand_help subcommand
20
- define_method(subcommand) { |*_| subcommand_class.start(subcommand_args) }
21
- end
22
-
23
- def self.subcommand_help(cmd)
24
- desc "#{cmd} help [COMMAND]", "Describe all subcommands or one specific subcommand."
25
- class_eval <<-RUBY
26
- def help(*args)
27
- if args.empty?
28
- EY.ui.say "usage: #{banner_base} #{cmd} COMMAND"
29
- EY.ui.say
30
- subcommands = self.class.printable_tasks.sort_by{|s| s[0] }
31
- subcommands.reject!{|t| t[0] =~ /#{cmd} help$/}
32
- EY.ui.print_help(subcommands)
33
- EY.ui.say self.class.send(:class_options_help, EY.ui)
34
- EY.ui.say "See #{banner_base} #{cmd} help COMMAND" +
35
- " for more information on a specific subcommand." if args.empty?
36
- else
37
- super
38
- end
39
- end
40
- RUBY
41
- end
42
-
43
- def subcommand_args
44
- @@original_args[1..-1]
45
- end
46
-
47
- def self.banner_base
48
- "ey"
49
- end
50
-
51
- def self.banner(task, task_help = false)
52
- scmd = EY::Thor.subcommands.invert[self]
53
- task = (task_help ? task.formatted_usage(self, false) : task.name)
54
- [banner_base, scmd, task].compact.join(" ")
55
- end
56
- end
57
-
4
+ module UtilityMethods
58
5
  protected
59
-
60
- def self.handle_no_task_error(task)
61
- if self.banner_base == "thor"
62
- raise UndefinedTaskError, "Could not find command #{task.inspect} in #{namespace.inspect} namespace."
63
- else
64
- raise UndefinedTaskError, "Could not find command #{task.inspect}."
65
- end
66
- end
67
-
68
- def self.exit_on_failure?
69
- true
70
- end
71
-
72
6
  def api
73
7
  @api ||= EY::CLI::API.new
74
8
  end
@@ -106,7 +40,7 @@ module EY
106
40
  api.apps.match_one!(app_name)
107
41
  else
108
42
  api.app_for_repo!(repo)
109
- end
43
+ end
110
44
  end
111
45
 
112
46
  def get_apps(all_apps = false)
@@ -116,5 +50,53 @@ module EY
116
50
  [api.app_for_repo(repo)].compact
117
51
  end
118
52
  end
53
+
54
+ end # UtilityMethods
55
+
56
+ class Thor < ::Thor
57
+ include UtilityMethods
58
+
59
+ no_tasks do
60
+ def self.subcommand_help(cmd)
61
+ desc "#{cmd} help [COMMAND]", "Describe all subcommands or one specific subcommand."
62
+ class_eval <<-RUBY
63
+ def help(*args)
64
+ if args.empty?
65
+ EY.ui.say "usage: #{banner_base} #{cmd} COMMAND"
66
+ EY.ui.say
67
+ subcommands = self.class.printable_tasks.sort_by{|s| s[0] }
68
+ subcommands.reject!{|t| t[0] =~ /#{cmd} help$/}
69
+ EY.ui.print_help(subcommands)
70
+ EY.ui.say self.class.send(:class_options_help, EY.ui)
71
+ EY.ui.say "See #{banner_base} #{cmd} help COMMAND" +
72
+ " for more information on a specific subcommand." if args.empty?
73
+ else
74
+ super
75
+ end
76
+ end
77
+ RUBY
78
+ end
79
+
80
+ def self.banner_base
81
+ "ey"
82
+ end
83
+
84
+ def self.banner(task, task_help = false, subcommand = false)
85
+ scmd = EY::Thor.subcommands.invert[self]
86
+ task = (task_help ? task.formatted_usage(self, false, subcommand) : task.name)
87
+ [banner_base, scmd, task].compact.join(" ")
88
+ end
89
+
90
+ def self.handle_no_task_error(task)
91
+ raise UndefinedTaskError, "Could not find command #{task.inspect}."
92
+ end
93
+ end
94
+
95
+ protected
96
+
97
+ def self.exit_on_failure?
98
+ true
99
+ end
100
+
119
101
  end
120
102
  end
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
@@ -97,6 +97,72 @@ describe "ey deploy" do
97
97
  @ssh_commands.last.should =~ /ey-deploy.*deploy/
98
98
  @ssh_commands.last.should_not =~ /--migrate/
99
99
  end
100
+
101
+ it "uses the default when --migrate is specified with no value" do
102
+ ey "deploy --migrate"
103
+ @ssh_commands.last.should match(/--migrate 'rake db:migrate'/)
104
+ end
105
+
106
+ context "customized in ey.yml" do
107
+ before { write_yaml({"environments" => {"giblets" => {
108
+ "migration_command" => 'thor fancy:migrate',
109
+ }}}) }
110
+ after { File.unlink 'ey.yml' }
111
+
112
+ it "migrates with the custom command by default" do
113
+ ey "deploy"
114
+ @ssh_commands.last.should =~ /--migrate 'thor fancy:migrate'/
115
+ end
116
+ end
117
+
118
+ context "disabled in ey.yml" do
119
+ before { write_yaml({"environments" => {"giblets" => {"migrate" => false}}}) }
120
+ after { File.unlink 'ey.yml' }
121
+
122
+ it "does not migrate by default" do
123
+ ey "deploy"
124
+ @ssh_commands.last.should =~ /ey-deploy.*deploy/
125
+ @ssh_commands.last.should_not =~ /--migrate/
126
+ end
127
+
128
+ it "can be turned back on with --migrate" do
129
+ ey "deploy --migrate 'rake fancy:migrate'"
130
+ @ssh_commands.last.should =~ /--migrate 'rake fancy:migrate'/
131
+ end
132
+
133
+ it "migrates with the default when --migrate is specified with no value" do
134
+ ey "deploy --migrate"
135
+ @ssh_commands.last.should match(/--migrate 'rake db:migrate'/)
136
+ end
137
+ end
138
+
139
+ context "explicitly enabled in ey.yml (the default)" do
140
+ before { write_yaml({"environments" => {"giblets" => {"migrate" => true}}}) }
141
+ after { File.unlink 'ey.yml' }
142
+
143
+ it "migrates with the default" do
144
+ ey "deploy"
145
+ @ssh_commands.last.should match(/--migrate 'rake db:migrate'/)
146
+ end
147
+ end
148
+
149
+ context "customized and disabled in ey.yml" do
150
+ before { write_yaml({"environments" => {"giblets" => {
151
+ "migrate" => false,
152
+ "migration_command" => "thor fancy:migrate",
153
+ }}}) }
154
+ after { File.unlink 'ey.yml' }
155
+
156
+ it "does not migrate by default" do
157
+ ey "deploy"
158
+ @ssh_commands.last.should_not match(/--migrate/)
159
+ end
160
+
161
+ it "migrates with the custom command when --migrate is specified with no value" do
162
+ ey "deploy --migrate"
163
+ @ssh_commands.last.should match(/--migrate 'thor fancy:migrate'/)
164
+ end
165
+ end
100
166
  end
101
167
 
102
168
  context "choosing something to deploy" do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 0
9
- version: 1.0.0
8
+ - 1
9
+ version: 1.0.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - EY Cloud Team
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-19 00:00:00 -07:00
17
+ date: 2010-07-22 00:00:00 -07:00
18
18
  default_executable: ey
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -45,8 +45,22 @@ dependencies:
45
45
  version_requirements: *id002
46
46
  - !ruby/object:Gem::Dependency
47
47
  prerelease: false
48
- name: escape
48
+ name: thor
49
49
  requirement: &id003 !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ - 13
56
+ - 8
57
+ version: 0.13.8
58
+ type: :runtime
59
+ version_requirements: *id003
60
+ - !ruby/object:Gem::Dependency
61
+ prerelease: false
62
+ name: escape
63
+ requirement: &id004 !ruby/object:Gem::Requirement
50
64
  requirements:
51
65
  - - ~>
52
66
  - !ruby/object:Gem::Version
@@ -56,11 +70,11 @@ dependencies:
56
70
  - 4
57
71
  version: 0.0.4
58
72
  type: :runtime
59
- version_requirements: *id003
73
+ version_requirements: *id004
60
74
  - !ruby/object:Gem::Dependency
61
75
  prerelease: false
62
76
  name: json
63
- requirement: &id004 !ruby/object:Gem::Requirement
77
+ requirement: &id005 !ruby/object:Gem::Requirement
64
78
  requirements:
65
79
  - - ~>
66
80
  - !ruby/object:Gem::Version
@@ -70,11 +84,11 @@ dependencies:
70
84
  - 0
71
85
  version: 1.4.0
72
86
  type: :runtime
73
- version_requirements: *id004
87
+ version_requirements: *id005
74
88
  - !ruby/object:Gem::Dependency
75
89
  prerelease: false
76
90
  name: rest-client
77
- requirement: &id005 !ruby/object:Gem::Requirement
91
+ requirement: &id006 !ruby/object:Gem::Requirement
78
92
  requirements:
79
93
  - - ~>
80
94
  - !ruby/object:Gem::Version
@@ -83,7 +97,7 @@ dependencies:
83
97
  - 4
84
98
  version: "1.4"
85
99
  type: :runtime
86
- version_requirements: *id005
100
+ version_requirements: *id006
87
101
  description: This gem allows you to deploy your rails application to the Engine Yard cloud directly from the command line.
88
102
  email: cloud@engineyard.com
89
103
  executables:
@@ -115,33 +129,6 @@ files:
115
129
  - lib/engineyard/repo.rb
116
130
  - lib/engineyard/ruby_ext.rb
117
131
  - lib/engineyard/thor.rb
118
- - lib/engineyard/vendor/thor/actions/create_file.rb
119
- - lib/engineyard/vendor/thor/actions/directory.rb
120
- - lib/engineyard/vendor/thor/actions/empty_directory.rb
121
- - lib/engineyard/vendor/thor/actions/file_manipulation.rb
122
- - lib/engineyard/vendor/thor/actions/inject_into_file.rb
123
- - lib/engineyard/vendor/thor/actions.rb
124
- - lib/engineyard/vendor/thor/base.rb
125
- - lib/engineyard/vendor/thor/core_ext/file_binary_read.rb
126
- - lib/engineyard/vendor/thor/core_ext/hash_with_indifferent_access.rb
127
- - lib/engineyard/vendor/thor/core_ext/ordered_hash.rb
128
- - lib/engineyard/vendor/thor/error.rb
129
- - lib/engineyard/vendor/thor/group.rb
130
- - lib/engineyard/vendor/thor/invocation.rb
131
- - lib/engineyard/vendor/thor/parser/argument.rb
132
- - lib/engineyard/vendor/thor/parser/arguments.rb
133
- - lib/engineyard/vendor/thor/parser/option.rb
134
- - lib/engineyard/vendor/thor/parser/options.rb
135
- - lib/engineyard/vendor/thor/parser.rb
136
- - lib/engineyard/vendor/thor/rake_compat.rb
137
- - lib/engineyard/vendor/thor/runner.rb
138
- - lib/engineyard/vendor/thor/shell/basic.rb
139
- - lib/engineyard/vendor/thor/shell/color.rb
140
- - lib/engineyard/vendor/thor/shell.rb
141
- - lib/engineyard/vendor/thor/task.rb
142
- - lib/engineyard/vendor/thor/util.rb
143
- - lib/engineyard/vendor/thor/version.rb
144
- - lib/engineyard/vendor/thor.rb
145
132
  - lib/engineyard/version.rb
146
133
  - lib/engineyard.rb
147
134
  - LICENSE
@@ -1,270 +0,0 @@
1
- require 'thor/base'
2
-
3
- # TODO: Update thor to allow for git-style CLI (git bisect run)
4
- class Thor
5
- class << self
6
- # Sets the default task when thor is executed without an explicit task to be called.
7
- #
8
- # ==== Parameters
9
- # meth<Symbol>:: name of the defaut task
10
- #
11
- def default_task(meth=nil)
12
- case meth
13
- when :none
14
- @default_task = 'help'
15
- when nil
16
- @default_task ||= from_superclass(:default_task, 'help')
17
- else
18
- @default_task = meth.to_s
19
- end
20
- end
21
-
22
- # Defines the usage and the description of the next task.
23
- #
24
- # ==== Parameters
25
- # usage<String>
26
- # description<String>
27
- #
28
- def desc(usage, description, options={})
29
- if options[:for]
30
- task = find_and_refresh_task(options[:for])
31
- task.usage = usage if usage
32
- task.description = description if description
33
- else
34
- @usage, @desc = usage, description
35
- end
36
- end
37
-
38
- # Defines the long description of the next task.
39
- #
40
- # ==== Parameters
41
- # long description<String>
42
- #
43
- def long_desc(long_description, options={})
44
- if options[:for]
45
- task = find_and_refresh_task(options[:for])
46
- task.long_description = long_description if long_description
47
- else
48
- @long_desc = long_description
49
- end
50
- end
51
-
52
- # Maps an input to a task. If you define:
53
- #
54
- # map "-T" => "list"
55
- #
56
- # Running:
57
- #
58
- # thor -T
59
- #
60
- # Will invoke the list task.
61
- #
62
- # ==== Parameters
63
- # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task.
64
- #
65
- def map(mappings=nil)
66
- @map ||= from_superclass(:map, {})
67
-
68
- if mappings
69
- mappings.each do |key, value|
70
- if key.respond_to?(:each)
71
- key.each {|subkey| @map[subkey] = value}
72
- else
73
- @map[key] = value
74
- end
75
- end
76
- end
77
-
78
- @map
79
- end
80
-
81
- # Declares the options for the next task to be declared.
82
- #
83
- # ==== Parameters
84
- # Hash[Symbol => Object]:: The hash key is the name of the option and the value
85
- # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
86
- # or :required (string). If you give a value, the type of the value is used.
87
- #
88
- def method_options(options=nil)
89
- @method_options ||= {}
90
- build_options(options, @method_options) if options
91
- @method_options
92
- end
93
-
94
- # Adds an option to the set of method options. If :for is given as option,
95
- # it allows you to change the options from a previous defined task.
96
- #
97
- # def previous_task
98
- # # magic
99
- # end
100
- #
101
- # method_option :foo => :bar, :for => :previous_task
102
- #
103
- # def next_task
104
- # # magic
105
- # end
106
- #
107
- # ==== Parameters
108
- # name<Symbol>:: The name of the argument.
109
- # options<Hash>:: Described below.
110
- #
111
- # ==== Options
112
- # :desc - Description for the argument.
113
- # :required - If the argument is required or not.
114
- # :default - Default value for this argument. It cannot be required and have default values.
115
- # :aliases - Aliases for this option.
116
- # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
117
- # :banner - String to show on usage notes.
118
- #
119
- def method_option(name, options={})
120
- scope = if options[:for]
121
- find_and_refresh_task(options[:for]).options
122
- else
123
- method_options
124
- end
125
-
126
- build_option(name, options, scope)
127
- end
128
-
129
- # Parses the task and options from the given args, instantiate the class
130
- # and invoke the task. This method is used when the arguments must be parsed
131
- # from an array. If you are inside Ruby and want to use a Thor class, you
132
- # can simply initialize it:
133
- #
134
- # script = MyScript.new(args, options, config)
135
- # script.invoke(:task, first_arg, second_arg, third_arg)
136
- #
137
- def start(original_args=ARGV, config={})
138
- super do |given_args|
139
- meth = given_args.first.to_s
140
-
141
- if !meth.empty? && (map[meth] || meth !~ /^\-/)
142
- given_args.shift
143
- else
144
- meth = nil
145
- end
146
-
147
- meth = normalize_task_name(meth)
148
- task = all_tasks[meth]
149
-
150
- if task
151
- args, opts = Thor::Options.split(given_args)
152
- config.merge!(:task_options => task.options)
153
- else
154
- args, opts = given_args, {}
155
- end
156
-
157
- task ||= Thor::Task::Dynamic.new(meth)
158
- trailing = args[Range.new(arguments.size, -1)]
159
- new(args, opts, config).invoke(task, trailing || [])
160
- end
161
- end
162
-
163
- # Prints help information for the given task.
164
- #
165
- # ==== Parameters
166
- # shell<Thor::Shell>
167
- # task_name<String>
168
- #
169
- def task_help(shell, task_name)
170
- meth = normalize_task_name(task_name)
171
- task = all_tasks[meth]
172
- handle_no_task_error(meth) unless task
173
-
174
- shell.say "Usage:"
175
- shell.say " #{banner(task, true)}"
176
- shell.say
177
- class_options_help(shell, nil => task.options.map { |_, o| o })
178
- if task.long_description
179
- shell.say "Description:"
180
- shell.print_wrapped(task.long_description, :ident => 2)
181
- else
182
- shell.say task.description
183
- end
184
- end
185
-
186
- # Prints help information for this class.
187
- #
188
- # ==== Parameters
189
- # shell<Thor::Shell>
190
- #
191
- def help(shell)
192
- list = printable_tasks
193
- Thor::Util.thor_classes_in(self).each do |klass|
194
- list += klass.printable_tasks(false)
195
- end
196
- list.sort!{ |a,b| a[0] <=> b[0] }
197
-
198
- shell.say "Tasks:"
199
- shell.print_table(list, :ident => 2, :truncate => true)
200
- shell.say
201
- class_options_help(shell)
202
- end
203
-
204
- # Returns tasks ready to be printed.
205
- def printable_tasks(all=true)
206
- (all ? all_tasks : tasks).map do |_, task|
207
- item = []
208
- item << banner(task)
209
- item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
210
- item
211
- end
212
- end
213
-
214
- def handle_argument_error(task, error) #:nodoc:
215
- raise InvocationError, "#{task.name.inspect} was called incorrectly. Call as #{task.formatted_usage(self, banner_base == "thor").inspect}."
216
- end
217
-
218
- protected
219
-
220
- # The banner for this class. You can customize it if you are invoking the
221
- # thor class by another ways which is not the Thor::Runner. It receives
222
- # the task that is going to be invoked and a boolean which indicates if
223
- # the namespace should be displayed as arguments.
224
- #
225
- def banner(task, task_help = false)
226
- "#{banner_base} #{task.formatted_usage(self, banner_base == "thor")}"
227
- end
228
-
229
- def baseclass #:nodoc:
230
- Thor
231
- end
232
-
233
- def create_task(meth) #:nodoc:
234
- if @usage && @desc
235
- tasks[meth.to_s] = Thor::Task.new(meth, @desc, @long_desc, @usage, method_options)
236
- @usage, @desc, @long_desc, @method_options = nil
237
- true
238
- elsif self.all_tasks[meth.to_s] || meth.to_sym == :method_missing
239
- true
240
- else
241
- puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
242
- "Call desc if you want this method to be available as task or declare it inside a " <<
243
- "no_tasks{} block. Invoked from #{caller[1].inspect}."
244
- false
245
- end
246
- end
247
-
248
- def initialize_added #:nodoc:
249
- class_options.merge!(method_options)
250
- @method_options = nil
251
- end
252
-
253
- # Receives a task name (can be nil), and try to get a map from it.
254
- # If a map can't be found use the sent name or the default task.
255
- #
256
- def normalize_task_name(meth) #:nodoc:
257
- meth = map[meth.to_s] || meth || default_task
258
- meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
259
- end
260
- end
261
-
262
- include Thor::Base
263
-
264
- map HELP_MAPPINGS => :help
265
-
266
- desc "help [TASK]", "Describe available tasks or one specific task"
267
- def help(task=nil)
268
- task ? self.class.task_help(shell, task) : self.class.help(shell)
269
- end
270
- end