engineyard 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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