engineyard 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/engineyard/cli.rb +11 -2
- data/lib/engineyard/model/environment.rb +36 -3
- data/lib/engineyard/model/instance.rb +1 -1
- data/lib/engineyard/thor.rb +50 -68
- data/lib/engineyard/version.rb +1 -1
- data/spec/ey/deploy_spec.rb +66 -0
- metadata +23 -36
- data/lib/engineyard/vendor/thor.rb +0 -270
- data/lib/engineyard/vendor/thor/actions.rb +0 -297
- data/lib/engineyard/vendor/thor/actions/create_file.rb +0 -105
- data/lib/engineyard/vendor/thor/actions/directory.rb +0 -93
- data/lib/engineyard/vendor/thor/actions/empty_directory.rb +0 -134
- data/lib/engineyard/vendor/thor/actions/file_manipulation.rb +0 -229
- data/lib/engineyard/vendor/thor/actions/inject_into_file.rb +0 -104
- data/lib/engineyard/vendor/thor/base.rb +0 -540
- data/lib/engineyard/vendor/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/engineyard/vendor/thor/core_ext/hash_with_indifferent_access.rb +0 -75
- data/lib/engineyard/vendor/thor/core_ext/ordered_hash.rb +0 -100
- data/lib/engineyard/vendor/thor/error.rb +0 -30
- data/lib/engineyard/vendor/thor/group.rb +0 -271
- data/lib/engineyard/vendor/thor/invocation.rb +0 -180
- data/lib/engineyard/vendor/thor/parser.rb +0 -4
- data/lib/engineyard/vendor/thor/parser/argument.rb +0 -67
- data/lib/engineyard/vendor/thor/parser/arguments.rb +0 -161
- data/lib/engineyard/vendor/thor/parser/option.rb +0 -128
- data/lib/engineyard/vendor/thor/parser/options.rb +0 -164
- data/lib/engineyard/vendor/thor/rake_compat.rb +0 -66
- data/lib/engineyard/vendor/thor/runner.rb +0 -314
- data/lib/engineyard/vendor/thor/shell.rb +0 -83
- data/lib/engineyard/vendor/thor/shell/basic.rb +0 -268
- data/lib/engineyard/vendor/thor/shell/color.rb +0 -108
- data/lib/engineyard/vendor/thor/task.rb +0 -102
- data/lib/engineyard/vendor/thor/util.rb +0 -229
- data/lib/engineyard/vendor/thor/version.rb +0 -3
data/lib/engineyard/cli.rb
CHANGED
@@ -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
|
-
:
|
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
|
-
|
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,
|
39
|
-
|
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.
|
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,
|
data/lib/engineyard/thor.rb
CHANGED
@@ -1,74 +1,8 @@
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path("../vendor", __FILE__)
|
2
1
|
require 'thor'
|
3
2
|
|
4
3
|
module EY
|
5
|
-
|
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
|
data/lib/engineyard/version.rb
CHANGED
data/spec/ey/deploy_spec.rb
CHANGED
@@ -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
|
-
-
|
9
|
-
version: 1.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-
|
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:
|
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: *
|
73
|
+
version_requirements: *id004
|
60
74
|
- !ruby/object:Gem::Dependency
|
61
75
|
prerelease: false
|
62
76
|
name: json
|
63
|
-
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: *
|
87
|
+
version_requirements: *id005
|
74
88
|
- !ruby/object:Gem::Dependency
|
75
89
|
prerelease: false
|
76
90
|
name: rest-client
|
77
|
-
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: *
|
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
|