adhearsion 2.3.5 → 2.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +2 -0
- data/README.markdown +21 -2
- data/adhearsion.gemspec +5 -4
- data/features/cli_plugin.feature +41 -0
- data/features/cli_start.feature +12 -4
- data/features/step_definitions/cli_steps.rb +12 -0
- data/features/support/env.rb +1 -1
- data/features/support/utils.rb +0 -1
- data/lib/adhearsion.rb +4 -1
- data/lib/adhearsion/call.rb +92 -22
- data/lib/adhearsion/call_controller.rb +19 -15
- data/lib/adhearsion/call_controller/dial.rb +157 -25
- data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +8 -0
- data/lib/adhearsion/call_controller/output/async_player.rb +1 -1
- data/lib/adhearsion/call_controller/output/formatter.rb +1 -1
- data/lib/adhearsion/call_controller/output/player.rb +1 -1
- data/lib/adhearsion/calls.rb +2 -0
- data/lib/adhearsion/cli_commands.rb +3 -163
- data/lib/adhearsion/cli_commands/ahn_command.rb +141 -0
- data/lib/adhearsion/cli_commands/plugin_command.rb +74 -0
- data/lib/adhearsion/cli_commands/thor_errors.rb +36 -0
- data/lib/adhearsion/console.rb +14 -6
- data/lib/adhearsion/generators/app/templates/spec/call_controllers/simon_game_spec.rb +36 -36
- data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +1 -1
- data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +0 -1
- data/lib/adhearsion/generators/plugin/templates/spec/plugin-template/controller_methods_spec.rb.tt +1 -1
- data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +0 -1
- data/lib/adhearsion/logging.rb +5 -1
- data/lib/adhearsion/outbound_call.rb +16 -0
- data/lib/adhearsion/punchblock_plugin.rb +0 -2
- data/lib/adhearsion/punchblock_plugin/initializer.rb +7 -12
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +785 -32
- data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +10 -0
- data/spec/adhearsion/call_controller/output/async_player_spec.rb +1 -1
- data/spec/adhearsion/call_controller/output/player_spec.rb +1 -1
- data/spec/adhearsion/call_controller/output_spec.rb +3 -3
- data/spec/adhearsion/call_controller/record_spec.rb +1 -1
- data/spec/adhearsion/call_controller_spec.rb +13 -9
- data/spec/adhearsion/call_spec.rb +216 -51
- data/spec/adhearsion/calls_spec.rb +1 -1
- data/spec/adhearsion/console_spec.rb +20 -9
- data/spec/adhearsion/outbound_call_spec.rb +40 -6
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +9 -21
- data/spec/adhearsion/punchblock_plugin_spec.rb +1 -1
- data/spec/adhearsion/router_spec.rb +1 -1
- data/spec/spec_helper.rb +11 -15
- data/spec/support/call_controller_test_helpers.rb +2 -2
- data/spec/support/punchblock_mocks.rb +2 -2
- metadata +41 -16
@@ -54,7 +54,11 @@ module Adhearsion
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
# @return [Call] The call object on which the controller is executing
|
58
|
+
attr_reader :call
|
59
|
+
|
60
|
+
# @return [Hash] The controller's metadata provided at invocation
|
61
|
+
attr_reader :metadata
|
58
62
|
|
59
63
|
# @private
|
60
64
|
attr_reader :block
|
@@ -105,7 +109,7 @@ module Adhearsion
|
|
105
109
|
execute_callbacks :before_call
|
106
110
|
run
|
107
111
|
rescue Call::Hangup
|
108
|
-
logger.info "Call was hung up"
|
112
|
+
logger.info "Call was hung up while executing a controller"
|
109
113
|
rescue SyntaxError, StandardError => e
|
110
114
|
Events.trigger :exception, [e, logger]
|
111
115
|
ensure
|
@@ -156,18 +160,6 @@ module Adhearsion
|
|
156
160
|
@after_call ||= execute_callbacks :after_call
|
157
161
|
end
|
158
162
|
|
159
|
-
#
|
160
|
-
# Hangup the call, and execute after_call callbacks
|
161
|
-
#
|
162
|
-
# @param [Hash] headers
|
163
|
-
#
|
164
|
-
def hangup(headers = nil)
|
165
|
-
block_until_resumed
|
166
|
-
call.hangup headers
|
167
|
-
after_call
|
168
|
-
raise Call::Hangup
|
169
|
-
end
|
170
|
-
|
171
163
|
# @private
|
172
164
|
def write_and_await_response(command)
|
173
165
|
block_until_resumed
|
@@ -195,6 +187,17 @@ module Adhearsion
|
|
195
187
|
call.answer(*args)
|
196
188
|
end
|
197
189
|
|
190
|
+
#
|
191
|
+
# Hangup the call, and execute after_call callbacks
|
192
|
+
#
|
193
|
+
# @param [Hash] headers
|
194
|
+
#
|
195
|
+
def hangup(headers = nil)
|
196
|
+
block_until_resumed
|
197
|
+
call.hangup headers
|
198
|
+
raise Call::Hangup
|
199
|
+
end
|
200
|
+
|
198
201
|
#
|
199
202
|
# Reject the call
|
200
203
|
#
|
@@ -203,6 +206,7 @@ module Adhearsion
|
|
203
206
|
def reject(*args)
|
204
207
|
block_until_resumed
|
205
208
|
call.reject(*args)
|
209
|
+
raise Call::Hangup
|
206
210
|
end
|
207
211
|
|
208
212
|
#
|
@@ -238,7 +242,7 @@ module Adhearsion
|
|
238
242
|
block_until_resumed
|
239
243
|
async = (target.is_a?(Hash) ? target : options).delete :async
|
240
244
|
join_command = call.join target, options
|
241
|
-
waiter = join_command.
|
245
|
+
waiter = join_command.call_uri || join_command.mixer_name
|
242
246
|
if async
|
243
247
|
call.wait_for_joined waiter
|
244
248
|
else
|
@@ -33,7 +33,7 @@ module Adhearsion
|
|
33
33
|
# @option options [Numeric] :for this option can be thought of best as a timeout.
|
34
34
|
# i.e. timeout after :for if no one answers the call
|
35
35
|
#
|
36
|
-
# @option options [CallController] :confirm the controller to execute on
|
36
|
+
# @option options [CallController] :confirm the controller to execute on the first outbound call to be answered, to give an opportunity to screen the call. The calls will be joined if the outbound call is still active after this controller completes.
|
37
37
|
# @option options [Hash] :confirm_metadata Metadata to set on the confirmation controller before executing it. This is shared between all calls if dialing multiple endpoints; if you care about it being mutated, you should provide an immutable value (using eg https://github.com/harukizaemon/hamster).
|
38
38
|
#
|
39
39
|
# @example Make a call to the PSTN using my SIP provider for VoIP termination
|
@@ -47,8 +47,22 @@ module Adhearsion
|
|
47
47
|
#
|
48
48
|
# @return [DialStatus] the status of the dial operation
|
49
49
|
#
|
50
|
-
def dial(to, options = {}
|
51
|
-
dial = Dial.new to, options,
|
50
|
+
def dial(to, options = {})
|
51
|
+
dial = Dial.new to, options, call
|
52
|
+
dial.run
|
53
|
+
dial.await_completion
|
54
|
+
dial.cleanup_calls
|
55
|
+
dial.status
|
56
|
+
end
|
57
|
+
|
58
|
+
# Dial one or more third parties and join one to this call after execution of a confirmation controller.
|
59
|
+
# Confirmation will be attempted on all answered calls, and calls will be allowed to progress through confirmation in parallel. The first to complete confirmation will be joined to the A-leg, with the others being hung up.
|
60
|
+
#
|
61
|
+
# @option options [CallController] :apology controller to execute on calls which lose the race to complete confirmation before they are hung up
|
62
|
+
#
|
63
|
+
# @see #dial
|
64
|
+
def dial_and_confirm(to, options = {})
|
65
|
+
dial = ParallelConfirmationDial.new to, options, call
|
52
66
|
dial.run
|
53
67
|
dial.await_completion
|
54
68
|
dial.cleanup_calls
|
@@ -58,9 +72,9 @@ module Adhearsion
|
|
58
72
|
class Dial
|
59
73
|
attr_accessor :status
|
60
74
|
|
61
|
-
def initialize(to, options,
|
75
|
+
def initialize(to, options, call)
|
62
76
|
raise Call::Hangup unless call.alive? && call.active?
|
63
|
-
@options, @
|
77
|
+
@options, @call = options, call
|
64
78
|
@targets = to.respond_to?(:has_key?) ? to : Array(to)
|
65
79
|
set_defaults
|
66
80
|
end
|
@@ -68,7 +82,7 @@ module Adhearsion
|
|
68
82
|
def set_defaults
|
69
83
|
@status = DialStatus.new
|
70
84
|
|
71
|
-
@latch
|
85
|
+
@latch = CountDownLatch.new @targets.size
|
72
86
|
|
73
87
|
@options[:from] ||= @call.from
|
74
88
|
|
@@ -93,38 +107,43 @@ module Adhearsion
|
|
93
107
|
@calls = @targets.map do |target, specific_options|
|
94
108
|
new_call = OutboundCall.new
|
95
109
|
|
110
|
+
join_status = JoinStatus.new
|
111
|
+
status.joins[new_call] = join_status
|
112
|
+
|
96
113
|
new_call.on_end do |event|
|
97
114
|
@latch.countdown! unless new_call["dial_countdown_#{@call.id}"]
|
98
|
-
|
115
|
+
if event.reason == :error
|
116
|
+
status.error!
|
117
|
+
join_status.errored!
|
118
|
+
end
|
99
119
|
end
|
100
120
|
|
101
121
|
new_call.on_answer do |event|
|
102
|
-
|
103
|
-
begin
|
104
|
-
next if call_to_hangup.id == new_call.id
|
105
|
-
logger.debug "#dial hanging up call #{call_to_hangup.id} because this call has been answered by another channel"
|
106
|
-
call_to_hangup.hangup
|
107
|
-
rescue Celluloid::DeadActorError
|
108
|
-
# This actor may previously have been shut down due to the call ending
|
109
|
-
end
|
110
|
-
end
|
122
|
+
pre_confirmation_tasks new_call
|
111
123
|
|
112
124
|
new_call.on_unjoined @call do |unjoined|
|
113
125
|
new_call["dial_countdown_#{@call.id}"] = true
|
126
|
+
join_status.ended
|
114
127
|
@latch.countdown!
|
115
128
|
end
|
116
129
|
|
117
130
|
if @confirmation_controller
|
118
131
|
status.unconfirmed!
|
119
|
-
|
120
|
-
|
132
|
+
join_status.unconfirmed!
|
133
|
+
condition = Celluloid::Condition.new
|
134
|
+
new_call.execute_controller @confirmation_controller.new(new_call, @confirmation_metadata), lambda { |call| condition.broadcast }
|
135
|
+
condition.wait
|
121
136
|
end
|
122
137
|
|
123
|
-
if new_call.alive? && new_call.active?
|
124
|
-
logger.
|
138
|
+
if new_call.alive? && new_call.active? && status.result != :answer
|
139
|
+
logger.info "#dial joining call #{new_call.id} to #{@call.id}"
|
140
|
+
pre_join_tasks new_call
|
125
141
|
@call.answer
|
142
|
+
join_status.started
|
126
143
|
new_call.join @call
|
127
|
-
status.answer!
|
144
|
+
status.answer!(new_call)
|
145
|
+
elsif status.result == :answer
|
146
|
+
join_status.lost_confirmation!
|
128
147
|
end
|
129
148
|
end
|
130
149
|
|
@@ -148,8 +167,18 @@ module Adhearsion
|
|
148
167
|
end
|
149
168
|
|
150
169
|
def cleanup_calls
|
151
|
-
|
152
|
-
|
170
|
+
calls_to_hangup = @calls.map do |call|
|
171
|
+
begin
|
172
|
+
[call.id, call] if call.active?
|
173
|
+
rescue Celluloid::DeadActorError
|
174
|
+
end
|
175
|
+
end.compact
|
176
|
+
if calls_to_hangup.size.zero?
|
177
|
+
logger.info "#dial finished with no remaining outbound calls"
|
178
|
+
return
|
179
|
+
end
|
180
|
+
logger.info "#dial finished. Hanging up #{calls_to_hangup.size} outbound calls which are still active: #{calls_to_hangup.map(&:first).join ", "}."
|
181
|
+
calls_to_hangup.each do |id, outbound_call|
|
153
182
|
begin
|
154
183
|
outbound_call.hangup
|
155
184
|
rescue Celluloid::DeadActorError
|
@@ -157,15 +186,66 @@ module Adhearsion
|
|
157
186
|
end
|
158
187
|
end
|
159
188
|
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def pre_confirmation_tasks(call)
|
193
|
+
on_all_except call do |target_call|
|
194
|
+
logger.info "#dial hanging up call #{target_call.id} because this call has been answered by another channel"
|
195
|
+
target_call.hangup
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def pre_join_tasks(call)
|
200
|
+
end
|
201
|
+
|
202
|
+
def on_all_except(call)
|
203
|
+
@calls.each do |target_call, _|
|
204
|
+
begin
|
205
|
+
next if target_call.id == call.id
|
206
|
+
yield target_call
|
207
|
+
rescue Celluloid::DeadActorError
|
208
|
+
# This actor may previously have been shut down due to the call ending
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class ParallelConfirmationDial < Dial
|
215
|
+
def set_defaults
|
216
|
+
super
|
217
|
+
@apology_controller = @options.delete :apology
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def pre_confirmation_tasks(call)
|
223
|
+
end
|
224
|
+
|
225
|
+
def pre_join_tasks(call)
|
226
|
+
on_all_except call do |target_call|
|
227
|
+
if @apology_controller
|
228
|
+
logger.info "#dial apologising to call #{target_call.id} because this call has been confirmed by another channel"
|
229
|
+
target_call.async.execute_controller @apology_controller.new(target_call, @confirmation_metadata), ->(call) { call.hangup }
|
230
|
+
else
|
231
|
+
logger.info "#dial hanging up call #{target_call.id} because this call has been confirmed by another channel"
|
232
|
+
target_call.hangup
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
160
236
|
end
|
161
237
|
|
162
238
|
class DialStatus
|
163
239
|
# The collection of calls created during the dial operation
|
164
|
-
attr_accessor :calls
|
240
|
+
attr_accessor :calls, :joined_call
|
241
|
+
|
242
|
+
# A collection of status objects indexed by call. Provides status on the joins such as duration
|
243
|
+
attr_accessor :joins
|
165
244
|
|
166
245
|
# @private
|
167
246
|
def initialize
|
168
247
|
@result = nil
|
248
|
+
@joins = {}
|
169
249
|
end
|
170
250
|
|
171
251
|
#
|
@@ -177,7 +257,8 @@ module Adhearsion
|
|
177
257
|
end
|
178
258
|
|
179
259
|
# @private
|
180
|
-
def answer!
|
260
|
+
def answer!(call)
|
261
|
+
@joined_call = call
|
181
262
|
@result = :answer
|
182
263
|
end
|
183
264
|
|
@@ -197,6 +278,57 @@ module Adhearsion
|
|
197
278
|
end
|
198
279
|
end
|
199
280
|
|
281
|
+
class JoinStatus
|
282
|
+
# The time at which the calls were joined
|
283
|
+
attr_accessor :start_time
|
284
|
+
|
285
|
+
# Time at which the join was broken
|
286
|
+
attr_accessor :end_time
|
287
|
+
|
288
|
+
def initialize
|
289
|
+
@result = :no_answer
|
290
|
+
end
|
291
|
+
|
292
|
+
# The result of the attempt to join calls
|
293
|
+
# Can be:
|
294
|
+
# * :joined - The calls were sucessfully joined
|
295
|
+
# * :no_answer - The attempt to dial the third-party was cancelled before they answered
|
296
|
+
# * :unconfirmed - The callee did not complete confirmation
|
297
|
+
# * :lost_confirmation - The callee completed confirmation, but was beaten by another
|
298
|
+
# * :error - The call ended with some error
|
299
|
+
attr_reader :result
|
300
|
+
|
301
|
+
# The duration for which the calls were joined. Does not include time spent in confirmation controllers or after being separated.
|
302
|
+
def duration
|
303
|
+
if start_time && end_time
|
304
|
+
end_time - start_time
|
305
|
+
else
|
306
|
+
0.0
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def errored!
|
311
|
+
@result = :error
|
312
|
+
end
|
313
|
+
|
314
|
+
def unconfirmed!
|
315
|
+
@result = :unconfirmed
|
316
|
+
end
|
317
|
+
|
318
|
+
def lost_confirmation!
|
319
|
+
@result = :lost_confirmation
|
320
|
+
end
|
321
|
+
|
322
|
+
def started
|
323
|
+
@start_time = Time.now
|
324
|
+
@result = :joined
|
325
|
+
end
|
326
|
+
|
327
|
+
def ended
|
328
|
+
@end_time = Time.now
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
200
332
|
end
|
201
333
|
end
|
202
334
|
end
|
@@ -10,7 +10,7 @@ module Adhearsion
|
|
10
10
|
# @raises [PlaybackError] if (one of) the given argument(s) could not be played
|
11
11
|
#
|
12
12
|
def output(content, options = {})
|
13
|
-
options.merge! :ssml => content
|
13
|
+
options.merge! :ssml => content
|
14
14
|
component = new_output options
|
15
15
|
component.register_event_handler Punchblock::Event::Complete do |event|
|
16
16
|
controller.logger.error event if event.reason.is_a?(Punchblock::Event::Complete::Error)
|
@@ -8,7 +8,7 @@ module Adhearsion
|
|
8
8
|
class Formatter
|
9
9
|
|
10
10
|
def ssml_for_collection(collection)
|
11
|
-
collection.inject RubySpeech::SSML
|
11
|
+
collection.inject RubySpeech::SSML.draw do |doc, argument|
|
12
12
|
doc + case argument
|
13
13
|
when Hash
|
14
14
|
ssml_for argument.delete(:value), argument
|
@@ -10,7 +10,7 @@ module Adhearsion
|
|
10
10
|
# @raises [PlaybackError] if (one of) the given argument(s) could not be played
|
11
11
|
#
|
12
12
|
def output(content, options = {}, &block)
|
13
|
-
options.merge! :ssml => content
|
13
|
+
options.merge! :ssml => content
|
14
14
|
component = new_output options
|
15
15
|
if block
|
16
16
|
controller.execute_component_and_await_completion component, &block
|
data/lib/adhearsion/calls.rb
CHANGED
@@ -49,6 +49,8 @@ module Adhearsion
|
|
49
49
|
call_id = key call
|
50
50
|
remove_inactive_call call
|
51
51
|
return unless reason
|
52
|
+
Adhearsion::Events.trigger :exception, reason
|
53
|
+
logger.error "Call #{call_id} terminated abnormally due to #{reason}. Forcing hangup."
|
52
54
|
PunchblockPlugin.client.execute_command Punchblock::Command::Hangup.new, :async => true, :call_id => call_id
|
53
55
|
end
|
54
56
|
end
|
@@ -22,168 +22,8 @@ end
|
|
22
22
|
|
23
23
|
module Adhearsion
|
24
24
|
module CLI
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
map %w(-) => :start
|
29
|
-
|
30
|
-
check_unknown_options!
|
31
|
-
|
32
|
-
def self.exit_on_failure?
|
33
|
-
true
|
34
|
-
end
|
35
|
-
|
36
|
-
desc "create /path/to/directory", "Create a new Adhearsion application under the given path"
|
37
|
-
def create(path)
|
38
|
-
require 'adhearsion/generators/app/app_generator'
|
39
|
-
Generators::AppGenerator.start
|
40
|
-
end
|
41
|
-
|
42
|
-
desc "generate [generator_name] arguments", Generators.help
|
43
|
-
def generate(generator_name = nil, *args)
|
44
|
-
if generator_name
|
45
|
-
Generators.invoke generator_name
|
46
|
-
else
|
47
|
-
help 'generate'
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
desc "version", "Shows Adhearsion version"
|
52
|
-
def version
|
53
|
-
say "Adhearsion v#{Adhearsion::VERSION}"
|
54
|
-
exit 0
|
55
|
-
end
|
56
|
-
|
57
|
-
desc "start </path/to/directory>", "Start the Adhearsion server in the foreground with a console"
|
58
|
-
def start(path = nil)
|
59
|
-
start_app path, :console
|
60
|
-
end
|
61
|
-
|
62
|
-
desc "daemon </path/to/directory>", "Start the Adhearsion server in the background"
|
63
|
-
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
64
|
-
def daemon(path = nil)
|
65
|
-
start_app path, :daemon, options[:pidfile]
|
66
|
-
end
|
67
|
-
|
68
|
-
desc "stop </path/to/directory>", "Stop a running Adhearsion server"
|
69
|
-
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
70
|
-
def stop(path = nil)
|
71
|
-
execute_from_app_dir! path
|
72
|
-
|
73
|
-
pid_file = if options[:pidfile]
|
74
|
-
File.exists?(File.expand_path(options[:pidfile])) ?
|
75
|
-
options[:pidfile] :
|
76
|
-
File.join(path, options[:pidfile])
|
77
|
-
else
|
78
|
-
path = Dir.pwd
|
79
|
-
File.join path, Adhearsion::Initializer::DEFAULT_PID_FILE_NAME
|
80
|
-
end
|
81
|
-
pid_file = File.expand_path pid_file
|
82
|
-
|
83
|
-
begin
|
84
|
-
pid = File.read(pid_file).to_i
|
85
|
-
rescue
|
86
|
-
raise PIDReadError, pid_file
|
87
|
-
end
|
88
|
-
|
89
|
-
raise PIDReadError, pid_file if pid.nil?
|
90
|
-
|
91
|
-
say "Stopping Adhearsion server at #{path} with pid #{pid}"
|
92
|
-
waiting_timeout = Time.now + 15
|
93
|
-
begin
|
94
|
-
::Process.kill "TERM", pid
|
95
|
-
sleep 0.25 while process_exists?(pid) && Time.now < waiting_timeout
|
96
|
-
::Process.kill "KILL", pid
|
97
|
-
rescue Errno::ESRCH
|
98
|
-
end
|
99
|
-
|
100
|
-
File.delete pid_file if File.exists? pid_file
|
101
|
-
end
|
102
|
-
|
103
|
-
desc "restart </path/to/directory>", "Restart the Adhearsion server"
|
104
|
-
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
105
|
-
def restart(path = nil)
|
106
|
-
execute_from_app_dir! path
|
107
|
-
begin
|
108
|
-
invoke :stop
|
109
|
-
rescue PIDReadError => e
|
110
|
-
puts e.message
|
111
|
-
end
|
112
|
-
invoke :daemon
|
113
|
-
end
|
114
|
-
|
115
|
-
protected
|
116
|
-
|
117
|
-
def start_app(path, mode, pid_file = nil)
|
118
|
-
execute_from_app_dir! path
|
119
|
-
say "Starting Adhearsion server at #{Dir.pwd}"
|
120
|
-
Adhearsion::Initializer.start :mode => mode, :pid_file => pid_file
|
121
|
-
end
|
122
|
-
|
123
|
-
def execute_from_app_dir!(path)
|
124
|
-
return if in_app? and running_script_ahn?
|
125
|
-
|
126
|
-
path ||= Dir.pwd if in_app?
|
127
|
-
|
128
|
-
raise PathRequired, ARGV[0] if path.nil? or path.empty?
|
129
|
-
raise PathInvalid, path unless ScriptAhnLoader.in_ahn_application?(path)
|
130
|
-
|
131
|
-
Dir.chdir path do
|
132
|
-
args = ARGV.dup
|
133
|
-
args[1] = File.expand_path path
|
134
|
-
ScriptAhnLoader.exec_script_ahn! args
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def running_script_ahn?
|
139
|
-
$0.to_s == "script/ahn"
|
140
|
-
end
|
141
|
-
|
142
|
-
def in_app?
|
143
|
-
ScriptAhnLoader.in_ahn_application? or ScriptAhnLoader.in_ahn_application_subdirectory?
|
144
|
-
end
|
145
|
-
|
146
|
-
def process_exists?(pid = nil)
|
147
|
-
# FIXME: Raise some error here
|
148
|
-
return false if pid.nil?
|
149
|
-
`ps -p #{pid} | sed -e '1d'`.strip.empty?
|
150
|
-
end
|
151
|
-
|
152
|
-
def method_missing(action, *args)
|
153
|
-
help
|
154
|
-
raise UnknownCommand, [action, *args] * " "
|
155
|
-
end
|
156
|
-
end # AhnCommand
|
157
|
-
|
158
|
-
class UnknownCommand < Thor::Error
|
159
|
-
def initialize(cmd)
|
160
|
-
super "Unknown command: #{cmd}"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
class PathRequired < Thor::Error
|
165
|
-
def initialize(cmd)
|
166
|
-
super "A valid path is required for #{cmd}, unless run from an Adhearson app directory"
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
class UnknownGeneratorError < Thor::Error
|
171
|
-
def initialize(gentype)
|
172
|
-
puts "Please specify generator to use (#{Adhearsion::Generators.mappings.keys.join(", ")})"
|
173
|
-
super "Unknown command: #{gentype}"
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
class PathInvalid < Thor::Error
|
178
|
-
def initialize(path)
|
179
|
-
super "Directory #{path} does not belong to an Adhearsion project!"
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
class PIDReadError < Thor::Error
|
184
|
-
def initialize(path)
|
185
|
-
super "Could not read pid from the file #{path}"
|
186
|
-
end
|
187
|
-
end
|
25
|
+
require 'adhearsion/cli_commands/plugin_command'
|
26
|
+
require 'adhearsion/cli_commands/ahn_command'
|
27
|
+
require 'adhearsion/cli_commands/thor_errors'
|
188
28
|
end
|
189
29
|
end
|