capistrano_multiconfig_parallel 0.17.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/capistrano_multiconfig_parallel/application.rb +11 -20
- data/lib/capistrano_multiconfig_parallel/base.rb +38 -18
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_manager.rb +18 -22
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_worker.rb +18 -20
- data/lib/capistrano_multiconfig_parallel/celluloid/child_process.rb +9 -20
- data/lib/capistrano_multiconfig_parallel/celluloid/rake_worker.rb +8 -10
- data/lib/capistrano_multiconfig_parallel/celluloid/terminal_table.rb +3 -2
- data/lib/capistrano_multiconfig_parallel/celluloid/web_server.rb +3 -1
- data/lib/capistrano_multiconfig_parallel/classes/dependency_tracker.rb +6 -5
- data/lib/capistrano_multiconfig_parallel/classes/rake_hook_actor.rb +15 -8
- data/lib/capistrano_multiconfig_parallel/classes/standard_deploy.rb +5 -3
- data/lib/capistrano_multiconfig_parallel/cli.rb +3 -1
- data/lib/capistrano_multiconfig_parallel/helpers/application_helper.rb +22 -29
- data/lib/capistrano_multiconfig_parallel/helpers/configuration.rb +4 -8
- data/lib/capistrano_multiconfig_parallel/helpers/core_helper.rb +86 -63
- data/lib/capistrano_multiconfig_parallel/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a35d2e97aa86ca857d89790da96cfa0378f8c61e
|
4
|
+
data.tar.gz: 17f2c290edb9ae3bc40dbede9be2554237982186
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f902cda7987cd1c172bb59afce5a1b1f76a85194835508b8522b283ac4b9005772f3c50ac2c6f2aa443544ad32e100d1f22538d0621102139be4023e801899bd
|
7
|
+
data.tar.gz: 39602658bd7b01eed3fea2b4c5e2b48aa0db9fc97776ebd154c9773b2895817cf526ac9a4b1dd92d83adac47432afb2e994ed6b8ddcceba762ca2a72a88864a5
|
data/Gemfile.lock
CHANGED
@@ -18,14 +18,14 @@ module CapistranoMulticonfigParallel
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def start
|
21
|
-
verify_app_dependencies if multi_apps? &&
|
21
|
+
verify_app_dependencies if multi_apps? && app_configuration.application_dependencies.present?
|
22
22
|
check_before_starting
|
23
23
|
initialize_data
|
24
24
|
run
|
25
25
|
end
|
26
26
|
|
27
27
|
def verify_app_dependencies
|
28
|
-
wrong =
|
28
|
+
wrong = app_configuration.application_dependencies.find do |hash|
|
29
29
|
!@stage_apps.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !@stage_apps.include?(val) })
|
30
30
|
end
|
31
31
|
raise ArgumentError, "Invalid configuration for #{wrong.inspect}".red if wrong.present?
|
@@ -56,25 +56,16 @@ module CapistranoMulticonfigParallel
|
|
56
56
|
|
57
57
|
def custom_command?
|
58
58
|
if multi_apps?
|
59
|
-
!@stages.include?(@top_level_tasks.first) && custom_commands.
|
59
|
+
!@stages.include?(@top_level_tasks.first) && custom_commands.include?(@top_level_tasks.first)
|
60
60
|
else
|
61
|
-
!@stages.include?(@top_level_tasks.second) && @stages.include?(@top_level_tasks.first) && custom_commands.
|
61
|
+
!@stages.include?(@top_level_tasks.second) && @stages.include?(@top_level_tasks.first) && custom_commands.include?(@top_level_tasks.second)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def custom_commands
|
66
|
-
key = multi_apps? ? CapistranoMulticonfigParallel::MULTI_KEY : CapistranoMulticonfigParallel::SINGLE_KEY
|
67
|
-
CapistranoMulticonfigParallel::CUSTOM_COMMANDS[key]
|
68
|
-
end
|
69
|
-
|
70
65
|
def multi_apps?
|
71
66
|
@stages.find { |stage| stage.include?(':') }.present?
|
72
67
|
end
|
73
68
|
|
74
|
-
def configuration
|
75
|
-
CapistranoMulticonfigParallel.configuration
|
76
|
-
end
|
77
|
-
|
78
69
|
def initialize_data
|
79
70
|
@application = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[1]
|
80
71
|
@stage = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[0]
|
@@ -103,7 +94,7 @@ module CapistranoMulticonfigParallel
|
|
103
94
|
def check_before_starting
|
104
95
|
CapistranoMulticonfigParallel.enable_logging
|
105
96
|
@dependency_tracker = CapistranoMulticonfigParallel::DependencyTracker.new(Actor.current)
|
106
|
-
@default_stage =
|
97
|
+
@default_stage = app_configuration.development_stages.present? ? app_configuration.development_stages.first : 'development'
|
107
98
|
@condition = Celluloid::Condition.new
|
108
99
|
@manager = CapistranoMulticonfigParallel::CelluloidManager.new(Actor.current)
|
109
100
|
end
|
@@ -116,13 +107,13 @@ module CapistranoMulticonfigParallel
|
|
116
107
|
deploy_multiple_apps(apps, options)
|
117
108
|
deploy_app(options) if !custom_command? || !multi_apps?
|
118
109
|
rescue => e
|
119
|
-
|
110
|
+
log_error(e)
|
120
111
|
end
|
121
112
|
|
122
113
|
def process_jobs
|
123
114
|
return unless @jobs.present?
|
124
115
|
FileUtils.rm Dir["#{CapistranoMulticonfigParallel.log_directory}/worker_*.log"]
|
125
|
-
if
|
116
|
+
if app_configuration.multi_secvential.to_s.downcase == 'true'
|
126
117
|
@jobs.each { |job| CapistranoMulticonfigParallel::StandardDeploy.new(job) }
|
127
118
|
else
|
128
119
|
run_async_jobs
|
@@ -130,7 +121,7 @@ module CapistranoMulticonfigParallel
|
|
130
121
|
end
|
131
122
|
|
132
123
|
def tag_staging_exists? # check exists task from capistrano-gitflow
|
133
|
-
|
124
|
+
find_loaded_gem('capistrano-gitflow').present?
|
134
125
|
end
|
135
126
|
|
136
127
|
def fetch_multi_stages
|
@@ -167,7 +158,7 @@ module CapistranoMulticonfigParallel
|
|
167
158
|
app_name = (app.is_a?(Hash) && app[:app].present?) ? app[:app].camelcase : app
|
168
159
|
app_name = app_name.present? ? app_name : 'current application'
|
169
160
|
message = "Please write additional ENV options for #{app_name} for #{app_message}"
|
170
|
-
app_additional_env_options =
|
161
|
+
app_additional_env_options = ask_confirm(message, nil)
|
171
162
|
fetch_app_additional_env_options(app_additional_env_options)
|
172
163
|
end
|
173
164
|
|
@@ -190,7 +181,7 @@ module CapistranoMulticonfigParallel
|
|
190
181
|
options = options.stringify_keys
|
191
182
|
main_box_name = @argv['BOX'].blank? ? '' : @argv['BOX']
|
192
183
|
stage = options.fetch('stage', @default_stage)
|
193
|
-
if
|
184
|
+
if app_configuration.development_stages.include?(stage) && main_box_name.present? && /^[a-z0-9,]+/.match(main_box_name)
|
194
185
|
execute_on_multiple_boxes(main_box_name, options)
|
195
186
|
else
|
196
187
|
prepare_job(options)
|
@@ -211,7 +202,7 @@ module CapistranoMulticonfigParallel
|
|
211
202
|
end
|
212
203
|
|
213
204
|
def wait_jobs_termination
|
214
|
-
return if
|
205
|
+
return if app_configuration.multi_secvential.to_s.downcase == 'true'
|
215
206
|
result = @condition.wait
|
216
207
|
return unless result.present?
|
217
208
|
@manager.terminate
|
@@ -7,36 +7,56 @@ module CapistranoMulticonfigParallel
|
|
7
7
|
|
8
8
|
class << self
|
9
9
|
attr_accessor :logger, :original_args
|
10
|
-
|
11
10
|
include CapistranoMulticonfigParallel::Configuration
|
12
|
-
include CapistranoMulticonfigParallel::ApplicationHelper
|
13
|
-
include CapistranoMulticonfigParallel::CoreHelper
|
14
11
|
|
15
12
|
def enable_logging
|
16
13
|
enable_file_logging
|
17
|
-
|
18
|
-
Celluloid.logger = CapistranoMulticonfigParallel.logger
|
14
|
+
Celluloid.logger = logger
|
19
15
|
Celluloid.task_class = Celluloid::TaskThread
|
20
16
|
end
|
21
17
|
|
18
|
+
def detect_root
|
19
|
+
if find_env_multi_cap_root
|
20
|
+
Pathname.new(find_env_multi_cap_root)
|
21
|
+
elsif defined?(::Rails)
|
22
|
+
::Rails.root
|
23
|
+
else
|
24
|
+
try_detect_capfile
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_file
|
29
|
+
File.join(detect_root.to_s, 'config', 'multi_cap.yml')
|
30
|
+
end
|
31
|
+
|
32
|
+
def log_directory
|
33
|
+
File.join(detect_root.to_s, 'log')
|
34
|
+
end
|
35
|
+
|
36
|
+
def main_log_file
|
37
|
+
File.join(log_directory, 'multi_cap.log')
|
38
|
+
end
|
39
|
+
|
40
|
+
def custom_commands
|
41
|
+
['deploy_multi_stages']
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
22
46
|
def enable_file_logging
|
23
|
-
|
47
|
+
if configuration.multi_debug.to_s.downcase == 'true'
|
48
|
+
enable_main_log_file
|
49
|
+
self.logger = ::Logger.new(main_log_file)
|
50
|
+
else
|
51
|
+
self.logger ||= ::Logger.new(DevNull.new)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def enable_main_log_file
|
24
56
|
FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
|
25
57
|
FileUtils.touch(main_log_file) unless File.file?(main_log_file)
|
26
58
|
log_file = File.open(main_log_file, 'w')
|
27
59
|
log_file.sync = true
|
28
|
-
self.logger = ::Logger.new(main_log_file)
|
29
|
-
end
|
30
|
-
|
31
|
-
def custom_commands
|
32
|
-
{
|
33
|
-
'multi ' => {
|
34
|
-
stages: 'deploy_multi_stages'
|
35
|
-
},
|
36
|
-
'single' => {
|
37
|
-
stages: 'deploy_multi_stages'
|
38
|
-
}
|
39
|
-
}
|
40
60
|
end
|
41
61
|
end
|
42
62
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require_relative './celluloid_worker'
|
2
2
|
require_relative './terminal_table'
|
3
3
|
require_relative './web_server'
|
4
|
+
require_relative '../helpers/application_helper'
|
4
5
|
module CapistranoMulticonfigParallel
|
5
6
|
# rubocop:disable ClassLength
|
6
7
|
class CelluloidManager
|
7
8
|
include Celluloid
|
8
9
|
include Celluloid::Notifications
|
9
10
|
include Celluloid::Logger
|
10
|
-
|
11
|
-
cattr_accessor :debug_enabled
|
11
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
12
12
|
|
13
13
|
attr_accessor :jobs, :job_to_worker, :worker_to_job, :job_to_condition, :mutex, :registration_complete, :workers_terminated
|
14
14
|
|
@@ -34,19 +34,15 @@ module CapistranoMulticonfigParallel
|
|
34
34
|
@worker_to_job = {}
|
35
35
|
@job_to_condition = {}
|
36
36
|
@worker_supervisor.supervise_as(:terminal_server, CapistranoMulticonfigParallel::TerminalTable, Actor.current, @job_manager)
|
37
|
-
@worker_supervisor.supervise_as(:web_server, CapistranoMulticonfigParallel::WebServer,
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.debug_enabled?
|
41
|
-
debug_enabled
|
37
|
+
@worker_supervisor.supervise_as(:web_server, CapistranoMulticonfigParallel::WebServer, websocket_config)
|
42
38
|
end
|
43
39
|
|
44
|
-
def
|
40
|
+
def debug_websocket?
|
45
41
|
websocket_config['enable_debug'].to_s == 'true'
|
46
42
|
end
|
47
43
|
|
48
|
-
def
|
49
|
-
config =
|
44
|
+
def websocket_config
|
45
|
+
config = app_configuration[:websocket_server]
|
50
46
|
config.present? && config.is_a?(Hash) ? config.stringify_keys : {}
|
51
47
|
config['enable_debug'] = config.fetch('enable_debug', '').to_s == 'true'
|
52
48
|
config
|
@@ -74,7 +70,7 @@ module CapistranoMulticonfigParallel
|
|
74
70
|
def register_worker_for_job(job, worker)
|
75
71
|
job = job.stringify_keys
|
76
72
|
if job['id'].blank?
|
77
|
-
|
73
|
+
log_to_file("job id not found. delegating again the job #{job.inspect}")
|
78
74
|
delegate(job)
|
79
75
|
else
|
80
76
|
start_worker(job, worker)
|
@@ -85,7 +81,7 @@ module CapistranoMulticonfigParallel
|
|
85
81
|
worker.job_id = job['id'] if worker.job_id.blank?
|
86
82
|
@job_to_worker[job['id']] = worker
|
87
83
|
@worker_to_job[worker.mailbox.address] = job
|
88
|
-
|
84
|
+
log_to_file("worker #{worker.job_id} registed into manager")
|
89
85
|
Actor.current.link worker
|
90
86
|
worker.async.start_task unless syncronized_confirmation?
|
91
87
|
@registration_complete = true if @job_manager.jobs.size == @job_to_worker.size
|
@@ -107,12 +103,12 @@ module CapistranoMulticonfigParallel
|
|
107
103
|
until condition.present?
|
108
104
|
sleep(0.1) # keep current thread alive
|
109
105
|
end
|
110
|
-
|
106
|
+
log_to_file("all jobs have completed #{condition}")
|
111
107
|
Celluloid::Actor[:terminal_server].async.notify_time_change(CapistranoMulticonfigParallel::TerminalTable.topic, type: 'output') if Celluloid::Actor[:terminal_server].alive?
|
112
108
|
end
|
113
109
|
|
114
110
|
def apply_confirmations?
|
115
|
-
confirmations =
|
111
|
+
confirmations = app_configuration.task_confirmations
|
116
112
|
confirmations.is_a?(Array) && confirmations.present?
|
117
113
|
end
|
118
114
|
|
@@ -121,13 +117,13 @@ module CapistranoMulticonfigParallel
|
|
121
117
|
end
|
122
118
|
|
123
119
|
def apply_confirmation_for_worker(worker)
|
124
|
-
worker.alive? &&
|
120
|
+
worker.alive? && app_configuration.apply_stage_confirmation.include?(worker.env_name) && apply_confirmations?
|
125
121
|
end
|
126
122
|
|
127
123
|
def setup_worker_conditions(worker)
|
128
124
|
return unless apply_confirmation_for_worker(worker)
|
129
125
|
hash_conditions = {}
|
130
|
-
|
126
|
+
app_configuration.task_confirmations.each do |task|
|
131
127
|
hash_conditions[task] = { condition: Celluloid::Condition.new, status: 'unconfirmed' }
|
132
128
|
end
|
133
129
|
@job_to_condition[worker.job_id] = hash_conditions
|
@@ -135,7 +131,7 @@ module CapistranoMulticonfigParallel
|
|
135
131
|
|
136
132
|
def mark_completed_remaining_tasks(worker)
|
137
133
|
return unless apply_confirmation_for_worker(worker)
|
138
|
-
|
134
|
+
app_configuration.task_confirmations.each_with_index do |task, _index|
|
139
135
|
fake_result = proc { |sum| sum }
|
140
136
|
task_confirmation = @job_to_condition[worker.job_id][task]
|
141
137
|
if task_confirmation[:status] != 'confirmed'
|
@@ -147,7 +143,7 @@ module CapistranoMulticonfigParallel
|
|
147
143
|
|
148
144
|
def wait_task_confirmations_worker(worker)
|
149
145
|
return if !apply_confirmation_for_worker(worker) || !syncronized_confirmation?
|
150
|
-
|
146
|
+
app_configuration.task_confirmations.each_with_index do |task, _index|
|
151
147
|
result = wait_condition_for_task(worker.job_id, task)
|
152
148
|
confirm_task_approval(result, task, worker) if result.present?
|
153
149
|
end
|
@@ -158,9 +154,9 @@ module CapistranoMulticonfigParallel
|
|
158
154
|
end
|
159
155
|
|
160
156
|
def wait_task_confirmations
|
161
|
-
stage_apply =
|
157
|
+
stage_apply = app_configuration.apply_stage_confirmation.include?(@job_manager.stage)
|
162
158
|
return if !stage_apply || !syncronized_confirmation?
|
163
|
-
|
159
|
+
app_configuration.task_confirmations.each_with_index do |task, _index|
|
164
160
|
results = []
|
165
161
|
@jobs.pmap do |job_id, _job|
|
166
162
|
result = wait_condition_for_task(job_id, task)
|
@@ -269,11 +265,11 @@ module CapistranoMulticonfigParallel
|
|
269
265
|
|
270
266
|
def worker_died(worker, reason)
|
271
267
|
job = @worker_to_job[worker.mailbox.address]
|
272
|
-
|
268
|
+
log_to_file("worker job #{job} with mailbox #{worker.mailbox.inspect} died for reason: #{reason}")
|
273
269
|
@worker_to_job.delete(worker.mailbox.address)
|
274
270
|
return if job.blank? || job_failed?(job)
|
275
271
|
return unless job['action_name'] == 'deploy'
|
276
|
-
|
272
|
+
log_to_file "restarting #{job} on new worker"
|
277
273
|
job = job.merge(:action => 'deploy:rollback', 'worker_action' => 'worker_died')
|
278
274
|
delegate(job)
|
279
275
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative './child_process'
|
2
2
|
require_relative './state_machine'
|
3
|
+
require_relative '../helpers/application_helper'
|
3
4
|
module CapistranoMulticonfigParallel
|
4
5
|
# rubocop:disable ClassLength
|
5
6
|
# worker that will spawn a child process in order to execute a capistrano job and monitor that process
|
@@ -20,12 +21,13 @@ module CapistranoMulticonfigParallel
|
|
20
21
|
include Celluloid
|
21
22
|
include Celluloid::Notifications
|
22
23
|
include Celluloid::Logger
|
24
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
23
25
|
class TaskFailed < StandardError; end
|
24
26
|
|
25
27
|
attr_accessor :job, :manager, :job_id, :app_name, :env_name, :action_name, :env_options, :machine, :client, :task_argv,
|
26
28
|
:rake_tasks, :current_task_number, # tracking tasks
|
27
29
|
:successfull_subscription, :subscription_channel, :publisher_channel, # for subscriptions and publishing events
|
28
|
-
:job_termination_condition, :worker_state, :invocation_chain
|
30
|
+
:job_termination_condition, :worker_state, :invocation_chain, :filename, :worker_log
|
29
31
|
|
30
32
|
def work(job, manager)
|
31
33
|
@job = job
|
@@ -33,20 +35,16 @@ module CapistranoMulticonfigParallel
|
|
33
35
|
@manager = manager
|
34
36
|
@job_confirmation_conditions = []
|
35
37
|
process_job(job) if job.present?
|
36
|
-
|
38
|
+
log_to_file("worker #{@job_id} received #{job.inspect}")
|
37
39
|
@subscription_channel = "worker_#{@job_id}"
|
38
40
|
@machine = CapistranoMulticonfigParallel::StateMachine.new(job, Actor.current)
|
39
41
|
manager.register_worker_for_job(job, Actor.current)
|
40
42
|
end
|
41
43
|
|
42
|
-
def debug_enabled?
|
43
|
-
@manager.class.debug_enabled?
|
44
|
-
end
|
45
|
-
|
46
44
|
def start_task
|
47
45
|
@manager.setup_worker_conditions(Actor.current)
|
48
|
-
|
49
|
-
@client = CelluloidPubsub::Client.connect(actor: Actor.current, enable_debug: @manager.
|
46
|
+
log_to_file("exec worker #{@job_id} starts task with #{@job.inspect}")
|
47
|
+
@client = CelluloidPubsub::Client.connect(actor: Actor.current, enable_debug: @manager.debug_websocket?, channel: subscription_channel)
|
50
48
|
end
|
51
49
|
|
52
50
|
def publish_rake_event(data)
|
@@ -58,7 +56,7 @@ module CapistranoMulticonfigParallel
|
|
58
56
|
end
|
59
57
|
|
60
58
|
def on_message(message)
|
61
|
-
|
59
|
+
log_to_file("worker #{@job_id} received: #{message.inspect}")
|
62
60
|
if @client.succesfull_subscription?(message)
|
63
61
|
@successfull_subscription = true
|
64
62
|
execute_after_succesfull_subscription
|
@@ -96,10 +94,10 @@ module CapistranoMulticonfigParallel
|
|
96
94
|
end
|
97
95
|
|
98
96
|
def execute_deploy
|
99
|
-
|
97
|
+
log_to_file("invocation chain #{@job_id} is : #{@rake_tasks.inspect}")
|
100
98
|
check_child_proces
|
101
99
|
setup_task_arguments
|
102
|
-
|
100
|
+
log_to_file("worker #{@job_id} executes: #{generate_command}")
|
103
101
|
@child_process.async.work(generate_command, actor: Actor.current, silent: true)
|
104
102
|
@manager.wait_task_confirmations_worker(Actor.current)
|
105
103
|
end
|
@@ -115,7 +113,7 @@ module CapistranoMulticonfigParallel
|
|
115
113
|
end
|
116
114
|
|
117
115
|
def on_close(code, reason)
|
118
|
-
|
116
|
+
log_to_file("worker #{@job_id} websocket connection closed: #{code.inspect}, #{reason.inspect}")
|
119
117
|
end
|
120
118
|
|
121
119
|
def check_gitflow
|
@@ -128,13 +126,13 @@ module CapistranoMulticonfigParallel
|
|
128
126
|
check_gitflow
|
129
127
|
save_tasks_to_be_executed(message)
|
130
128
|
update_machine_state(message['task']) # if message['action'] == 'invoke'
|
131
|
-
|
129
|
+
log_to_file("worker #{@job_id} state is #{@machine.state}")
|
132
130
|
task_approval(message)
|
133
131
|
elsif message_is_for_stdout?(message)
|
134
132
|
result = Celluloid::Actor[:terminal_server].show_confirmation(message['question'], message['default'])
|
135
133
|
publish_rake_event(message.merge('action' => 'stdin', 'result' => result, 'client_action' => 'stdin'))
|
136
134
|
else
|
137
|
-
|
135
|
+
log_to_file(message, @job_id)
|
138
136
|
end
|
139
137
|
end
|
140
138
|
|
@@ -152,7 +150,7 @@ module CapistranoMulticonfigParallel
|
|
152
150
|
|
153
151
|
def task_approval(message)
|
154
152
|
job_conditions = @manager.job_to_condition[@job_id]
|
155
|
-
if job_conditions.present? &&
|
153
|
+
if job_conditions.present? && app_configuration.task_confirmations.include?(message['task']) && message['action'] == 'invoke'
|
156
154
|
task_confirmation = job_conditions[message['task']]
|
157
155
|
task_confirmation[:status] = 'confirmed'
|
158
156
|
task_confirmation[:condition].signal(message['task'])
|
@@ -162,13 +160,13 @@ module CapistranoMulticonfigParallel
|
|
162
160
|
end
|
163
161
|
|
164
162
|
def save_tasks_to_be_executed(message)
|
165
|
-
|
163
|
+
log_to_file("worler #{@job_id} current invocation chain : #{rake_tasks.inspect}")
|
166
164
|
rake_tasks << message['task'] if rake_tasks.last != message['task']
|
167
165
|
invocation_chain << message['task'] if invocation_chain.last != message['task']
|
168
166
|
end
|
169
167
|
|
170
168
|
def update_machine_state(name)
|
171
|
-
|
169
|
+
log_to_file("worker #{@job_id} triest to transition from #{@machine.state} to #{name}")
|
172
170
|
@machine.transitions.on(name.to_s, @machine.state => name.to_s)
|
173
171
|
@machine.go_to_transition(name.to_s)
|
174
172
|
raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task #{@action} failed ") if name == 'deploy:failed' # force worker to rollback
|
@@ -196,7 +194,7 @@ module CapistranoMulticonfigParallel
|
|
196
194
|
@env_options.each do |key, value|
|
197
195
|
array_options << "#{key}=#{value}" if value.present?
|
198
196
|
end
|
199
|
-
array_options << '--trace' if
|
197
|
+
array_options << '--trace' if app_debug_enabled?
|
200
198
|
args.each do |arg|
|
201
199
|
array_options << arg
|
202
200
|
end
|
@@ -236,11 +234,11 @@ module CapistranoMulticonfigParallel
|
|
236
234
|
|
237
235
|
def notify_finished(exit_status)
|
238
236
|
if exit_status.exitstatus != 0
|
239
|
-
|
237
|
+
log_to_file("worker #{job_id} tries to terminate")
|
240
238
|
raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task failed with exit status #{exit_status.inspect} ") # force worker to rollback
|
241
239
|
else
|
242
240
|
update_machine_state('FINISHED')
|
243
|
-
|
241
|
+
log_to_file("worker #{job_id} notifies manager has finished")
|
244
242
|
finish_worker
|
245
243
|
end
|
246
244
|
end
|
@@ -1,10 +1,13 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
2
|
+
require_relative '../helpers/core_helper'
|
1
3
|
module CapistranoMulticonfigParallel
|
2
4
|
# class that is used to execute the capistrano tasks and it is invoked by the celluloid worker
|
3
5
|
class ChildProcess
|
4
6
|
include Celluloid
|
5
7
|
include Celluloid::Logger
|
8
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
6
9
|
|
7
|
-
attr_accessor :actor, :pid, :exit_status, :process, :
|
10
|
+
attr_accessor :actor, :pid, :exit_status, :process, :job_id
|
8
11
|
|
9
12
|
finalizer :process_finalizer
|
10
13
|
|
@@ -12,8 +15,6 @@ module CapistranoMulticonfigParallel
|
|
12
15
|
@options = options
|
13
16
|
@actor = @options.fetch(:actor, nil)
|
14
17
|
@job_id = @actor.job_id
|
15
|
-
@debug_enabled = @actor.debug_enabled?
|
16
|
-
set_worker_log
|
17
18
|
EM.run do
|
18
19
|
EM.next_tick do
|
19
20
|
start_async_deploy(cmd, options)
|
@@ -23,24 +24,12 @@ module CapistranoMulticonfigParallel
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
EM.error_handler do|e|
|
26
|
-
|
27
|
-
|
27
|
+
log_to_file("Error during event loop for worker #{@job_id}: #{e.inspect}", @job_id)
|
28
|
+
log_to_file(e.backtrace, @job_id)
|
28
29
|
EM.stop
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
def set_worker_log
|
33
|
-
FileUtils.mkdir_p(CapistranoMulticonfigParallel.log_directory) unless File.directory?(CapistranoMulticonfigParallel.log_directory)
|
34
|
-
@filename = File.join(CapistranoMulticonfigParallel.log_directory, "worker_#{@actor.job_id}.log")
|
35
|
-
FileUtils.rm_rf(@filename) if File.file?(@filename) && !@actor.crashed?
|
36
|
-
@worker_log = ::Logger.new(@filename)
|
37
|
-
@worker_log.level = ::Logger::Severity::DEBUG
|
38
|
-
@worker_log.formatter = proc do |severity, datetime, progname, msg|
|
39
|
-
date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
40
|
-
"[#{date_format}] #{severity} (#{progname}): #{msg}\n"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
33
|
def process_finalizer
|
45
34
|
@timer.cancel
|
46
35
|
EM.stop if EM.reactor_running?
|
@@ -83,12 +72,12 @@ module CapistranoMulticonfigParallel
|
|
83
72
|
end
|
84
73
|
|
85
74
|
def on_exit(status)
|
86
|
-
|
75
|
+
log_to_file "Child process for worker #{@job_id} on_exit disconnected due to error #{status.inspect}"
|
87
76
|
@exit_status = status
|
88
77
|
end
|
89
78
|
|
90
79
|
def async_exception_handler(*data)
|
91
|
-
|
80
|
+
log_to_file "Child process for worker #{@job_id} async_exception_handler disconnected due to error #{data.inspect}"
|
92
81
|
io_callback('stderr', data)
|
93
82
|
@exit_status = 1
|
94
83
|
end
|
@@ -98,7 +87,7 @@ module CapistranoMulticonfigParallel
|
|
98
87
|
end
|
99
88
|
|
100
89
|
def io_callback(io, data)
|
101
|
-
|
90
|
+
log_to_file("#{io.upcase} ---- #{data}", @job_id)
|
102
91
|
end
|
103
92
|
end
|
104
93
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
1
2
|
module CapistranoMulticonfigParallel
|
2
3
|
# class that handles the rake task and waits for approval from the celluloid worker
|
3
4
|
# rubocop:disable ClassLength
|
4
5
|
class RakeWorker
|
5
6
|
include Celluloid
|
6
7
|
include Celluloid::Logger
|
8
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
7
9
|
|
8
10
|
attr_accessor :env, :client, :job_id, :action, :task,
|
9
11
|
:task_approved, :successfull_subscription,
|
@@ -50,11 +52,7 @@ module CapistranoMulticonfigParallel
|
|
50
52
|
|
51
53
|
def initialize_subscription
|
52
54
|
return if defined?(@client) && @client.present?
|
53
|
-
@client = CelluloidPubsub::Client.connect(actor: Actor.current, enable_debug:
|
54
|
-
end
|
55
|
-
|
56
|
-
def debug_enabled?
|
57
|
-
CapistranoMulticonfigParallel::CelluloidManager.debug_websocket?
|
55
|
+
@client = CelluloidPubsub::Client.connect(actor: Actor.current, enable_debug: false, channel: @subscription_channel)
|
58
56
|
end
|
59
57
|
|
60
58
|
def task_name
|
@@ -82,12 +80,12 @@ module CapistranoMulticonfigParallel
|
|
82
80
|
task_approval(message)
|
83
81
|
stdin_approval(message)
|
84
82
|
else
|
85
|
-
|
83
|
+
show_warning "unknown action: #{message.inspect}"
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
89
87
|
def log_debug(action, message)
|
90
|
-
|
88
|
+
log_to_file("Rake worker #{@job_id} received after #{action}: #{message}")
|
91
89
|
end
|
92
90
|
|
93
91
|
def msg_for_stdin?(message)
|
@@ -117,7 +115,7 @@ module CapistranoMulticonfigParallel
|
|
117
115
|
if @job_id.to_i == message['job_id'].to_i && message['result'].present?
|
118
116
|
@stdin_result = message['result']
|
119
117
|
else
|
120
|
-
|
118
|
+
show_warning "unknown invocation #{message.inspect}"
|
121
119
|
end
|
122
120
|
end
|
123
121
|
|
@@ -126,12 +124,12 @@ module CapistranoMulticonfigParallel
|
|
126
124
|
if @job_id.to_i == message['job_id'].to_i && message['task'] == task_name && message['approved'] == 'yes'
|
127
125
|
@task_approved = true
|
128
126
|
else
|
129
|
-
|
127
|
+
show_warning "unknown invocation #{message.inspect}"
|
130
128
|
end
|
131
129
|
end
|
132
130
|
|
133
131
|
def on_close(code, reason)
|
134
|
-
|
132
|
+
log_to_file("websocket connection closed: #{code.inspect}, #{reason.inspect}")
|
135
133
|
terminate
|
136
134
|
end
|
137
135
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
1
2
|
module CapistranoMulticonfigParallel
|
2
3
|
# class used to display the progress of each worker on terminal screen using a table
|
3
4
|
# rubocop:disable ClassLength
|
@@ -5,7 +6,7 @@ module CapistranoMulticonfigParallel
|
|
5
6
|
include Celluloid
|
6
7
|
include Celluloid::Notifications
|
7
8
|
include Celluloid::Logger
|
8
|
-
|
9
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
9
10
|
def self.topic
|
10
11
|
'sshkit_terminal'
|
11
12
|
end
|
@@ -44,7 +45,7 @@ module CapistranoMulticonfigParallel
|
|
44
45
|
|
45
46
|
def show_confirmation(message, default)
|
46
47
|
exclusive do
|
47
|
-
|
48
|
+
ask_confirm(message, default)
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
1
2
|
module CapistranoMulticonfigParallel
|
2
3
|
# class used to start the web server for websockets
|
3
4
|
class WebServer < CelluloidPubsub::WebServer
|
5
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
4
6
|
def initialize(*args)
|
5
7
|
super(*args)
|
6
8
|
rescue => exc
|
7
|
-
|
9
|
+
log_error(exc)
|
8
10
|
# fails silently
|
9
11
|
end
|
10
12
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require_relative './interactive_menu'
|
2
|
-
|
2
|
+
require_relative '../helpers/application_helper'
|
3
3
|
module CapistranoMulticonfigParallel
|
4
4
|
# class used to find application dependencies
|
5
5
|
class DependencyTracker
|
6
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
6
7
|
attr_accessor :job_manager
|
7
8
|
|
8
9
|
def initialize(job_manager)
|
@@ -15,7 +16,7 @@ module CapistranoMulticonfigParallel
|
|
15
16
|
if @job_manager.custom_command?
|
16
17
|
apps_selected = all_websites_return_applications_selected
|
17
18
|
applications = get_applications_to_deploy(action, apps_selected)
|
18
|
-
elsif
|
19
|
+
elsif app_configuration.application_dependencies.present?
|
19
20
|
if application.present?
|
20
21
|
applications = get_applications_to_deploy(action, [application.camelcase])
|
21
22
|
applications = applications.delete_if { |hash| hash['app'] == application }
|
@@ -31,7 +32,7 @@ module CapistranoMulticonfigParallel
|
|
31
32
|
private
|
32
33
|
|
33
34
|
def application_dependencies
|
34
|
-
deps =
|
35
|
+
deps = app_configuration.application_dependencies
|
35
36
|
deps.present? && deps.is_a?(Array) ? deps.map(&:stringify_keys) : []
|
36
37
|
end
|
37
38
|
|
@@ -68,7 +69,7 @@ module CapistranoMulticonfigParallel
|
|
68
69
|
|
69
70
|
def check_app_dependency_unique(applications_selected, apps_dependencies, applications_to_deploy, action)
|
70
71
|
return applications_to_deploy if applications_selected.blank? || apps_dependencies.blank? || (apps_dependencies.map { |app| app['app'] } - applications_to_deploy.map { |app| app['app'] }).blank?
|
71
|
-
apps_dependency_confirmation =
|
72
|
+
apps_dependency_confirmation = ask_confirm("Do you want to #{action} all dependencies also ?", 'Y/N')
|
72
73
|
applications_to_deploy = applications_to_deploy.concat(apps_dependencies) if apps_dependency_confirmation.present? && apps_dependency_confirmation.downcase == 'y'
|
73
74
|
applications_to_deploy
|
74
75
|
end
|
@@ -102,7 +103,7 @@ module CapistranoMulticonfigParallel
|
|
102
103
|
|
103
104
|
def print_frameworks_used(app_names, applications_to_deploy, action)
|
104
105
|
app_names.each { |app| puts "#{app}" }
|
105
|
-
apps_deploy_confirmation =
|
106
|
+
apps_deploy_confirmation = ask_confirm("Are you sure you want to #{action} these apps?", 'Y/N')
|
106
107
|
if apps_deploy_confirmation.blank? || (apps_deploy_confirmation.present? && apps_deploy_confirmation.downcase != 'y')
|
107
108
|
return []
|
108
109
|
elsif apps_deploy_confirmation.present? && apps_deploy_confirmation.downcase == 'y'
|
@@ -23,18 +23,26 @@ module CapistranoMulticonfigParallel
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
+
def output_stream
|
27
|
+
CapistranoMulticonfigParallel::OutputStream
|
28
|
+
end
|
29
|
+
|
30
|
+
def input_stream
|
31
|
+
CapistranoMulticonfigParallel::InputStream
|
32
|
+
end
|
33
|
+
|
26
34
|
def actor_execute_block(&block)
|
27
35
|
stringio = StringIO.new
|
28
|
-
|
29
|
-
|
36
|
+
output_stream.hook(stringio)
|
37
|
+
input_stream.hook(actor, stringio)
|
30
38
|
block.call
|
31
|
-
|
32
|
-
|
39
|
+
input_stream.unhook
|
40
|
+
output_stream.unhook
|
33
41
|
end
|
34
42
|
|
35
43
|
def actor_start_working
|
36
44
|
if actor.blank?
|
37
|
-
|
45
|
+
supervise_actor
|
38
46
|
actor.work(@env, actor_id: rake_actor_id, job_id: job_id, task: @task)
|
39
47
|
else
|
40
48
|
actor.publish_new_work(@env, task: @task)
|
@@ -42,9 +50,8 @@ module CapistranoMulticonfigParallel
|
|
42
50
|
end
|
43
51
|
|
44
52
|
def supervise_actor
|
45
|
-
|
46
|
-
|
47
|
-
job_id: job_id) if actor.blank?
|
53
|
+
return unless actor.blank?
|
54
|
+
CapistranoMulticonfigParallel::RakeWorker.supervise_as(rake_actor_id)
|
48
55
|
end
|
49
56
|
|
50
57
|
def actor
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require_relative '../helpers/application_helper'
|
2
3
|
module CapistranoMulticonfigParallel
|
3
4
|
# class used to find application dependencies
|
4
5
|
class StandardDeploy
|
5
6
|
include FileUtils
|
7
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
6
8
|
|
7
9
|
attr_reader :app, :stage, :action, :task_arguments, :env_options
|
8
10
|
def initialize(options)
|
@@ -40,9 +42,9 @@ module CapistranoMulticonfigParallel
|
|
40
42
|
command = build_capistrano_task(action)
|
41
43
|
puts("\n\n\n Executing '#{command}' \n\n\n .")
|
42
44
|
sh("#{command}")
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
rescue => ex
|
46
|
+
log_error(ex)
|
47
|
+
execute_standard_deploy('deploy:rollback') if action.blank? && @name == 'deploy'
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
@@ -4,6 +4,8 @@ module CapistranoMulticonfigParallel
|
|
4
4
|
# this is the class that will be invoked from terminal , and willl use the invoke task as the primary function.
|
5
5
|
class CLI
|
6
6
|
class << self
|
7
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
8
|
+
|
7
9
|
# method used to start
|
8
10
|
def start
|
9
11
|
verify_validation
|
@@ -26,7 +28,7 @@ module CapistranoMulticonfigParallel
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def verify_validation
|
29
|
-
|
31
|
+
check_terminal_tty
|
30
32
|
CapistranoMulticonfigParallel.original_args = ARGV.dup
|
31
33
|
CapistranoMulticonfigParallel.configuration_valid?
|
32
34
|
end
|
@@ -2,44 +2,37 @@ require_relative './core_helper'
|
|
2
2
|
module CapistranoMulticonfigParallel
|
3
3
|
# class that holds the options that are configurable for this gem
|
4
4
|
module ApplicationHelper
|
5
|
-
|
6
|
-
included do
|
7
|
-
def app_configuration
|
8
|
-
CapistranoMulticonfigParallel.configuration
|
9
|
-
end
|
10
|
-
|
11
|
-
def change_config_type(type)
|
12
|
-
['boolean'].include?(type) ? type.delete(':').to_sym : type.constantize
|
13
|
-
end
|
5
|
+
include CapistranoMulticonfigParallel::CoreHelper
|
14
6
|
|
15
|
-
|
16
|
-
return unless value.present?
|
17
|
-
value = value.delete("\r\n").delete("\n")
|
18
|
-
value = value.gsub(/\s+/, ' ').strip if value.present?
|
19
|
-
value
|
20
|
-
end
|
7
|
+
module_function
|
21
8
|
|
22
|
-
|
23
|
-
|
9
|
+
def strip_characters_from_string(value)
|
10
|
+
return unless value.present?
|
11
|
+
value = value.delete("\r\n").delete("\n")
|
12
|
+
value = value.gsub(/\s+/, ' ').strip if value.present?
|
13
|
+
value
|
14
|
+
end
|
24
15
|
|
25
|
-
|
26
|
-
|
16
|
+
def parse_task_string(string) # :nodoc:
|
17
|
+
/^([^\[]+)(?:\[(.*)\])$/ =~ string.to_s
|
27
18
|
|
28
|
-
|
29
|
-
|
19
|
+
name = Regexp.last_match(1)
|
20
|
+
remaining_args = Regexp.last_match(2)
|
30
21
|
|
31
|
-
|
22
|
+
return string, [] unless name
|
23
|
+
return name, [] if remaining_args.empty?
|
32
24
|
|
33
|
-
|
34
|
-
/((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args
|
25
|
+
args = []
|
35
26
|
|
36
|
-
|
37
|
-
|
38
|
-
break if remaining_args.blank?
|
39
|
-
end
|
27
|
+
loop do
|
28
|
+
/((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args
|
40
29
|
|
41
|
-
|
30
|
+
remaining_args = Regexp.last_match(2)
|
31
|
+
args << Regexp.last_match(1).gsub(/\\(.)/, '\1')
|
32
|
+
break if remaining_args.blank?
|
42
33
|
end
|
34
|
+
|
35
|
+
[name, args]
|
43
36
|
end
|
44
37
|
end
|
45
38
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require_relative './application_helper'
|
1
2
|
module CapistranoMulticonfigParallel
|
2
3
|
# class that holds the options that are configurable for this gem
|
3
4
|
module Configuration
|
4
5
|
extend ActiveSupport::Concern
|
6
|
+
include CapistranoMulticonfigParallel::ApplicationHelper
|
5
7
|
|
6
8
|
included do
|
7
9
|
attr_reader :configuration
|
@@ -13,8 +15,8 @@ module CapistranoMulticonfigParallel
|
|
13
15
|
|
14
16
|
def fetch_configuration
|
15
17
|
@fetched_config = Configliere::Param.new
|
16
|
-
|
17
|
-
param_type =
|
18
|
+
default_internal_config.each do |param|
|
19
|
+
param_type = find_config_type(param['type'])
|
18
20
|
@fetched_config.define param['name'], type: param_type, description: param['description'], default: param['default']
|
19
21
|
end
|
20
22
|
|
@@ -32,11 +34,6 @@ module CapistranoMulticonfigParallel
|
|
32
34
|
@fetched_config.resolve!
|
33
35
|
end
|
34
36
|
|
35
|
-
def command_line_params
|
36
|
-
@default_config ||= YAML.load_file(File.join(internal_config_directory, 'default.yml'))['default_config']
|
37
|
-
@default_config
|
38
|
-
end
|
39
|
-
|
40
37
|
def verify_array_of_strings(value)
|
41
38
|
return true if value.blank?
|
42
39
|
value.reject(&:blank?)
|
@@ -82,7 +79,6 @@ module CapistranoMulticonfigParallel
|
|
82
79
|
check_boolean_props(c, %w(multi_debug multi_secvential websocket_server.enable_debug))
|
83
80
|
check_array_props(c, %w(task_confirmations development_stages apply_stage_confirmation))
|
84
81
|
verify_application_dependencies(c, 'application_dependencies', %w(app priority dependencies))
|
85
|
-
CapistranoMulticonfigParallel::CelluloidManager.debug_enabled = true if c[:multi_debug].to_s.downcase == 'true'
|
86
82
|
end
|
87
83
|
end
|
88
84
|
end
|
@@ -1,82 +1,105 @@
|
|
1
1
|
module CapistranoMulticonfigParallel
|
2
2
|
# class that holds the options that are configurable for this gem
|
3
3
|
module CoreHelper
|
4
|
-
|
5
|
-
included do
|
6
|
-
def config_file
|
7
|
-
File.join(detect_root.to_s, 'config', 'multi_cap.yml')
|
8
|
-
end
|
4
|
+
module_function
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
def internal_config_directory
|
7
|
+
File.join(root.to_s, 'capistrano_multiconfig_parallel', 'configuration')
|
8
|
+
end
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
def internal_config_file
|
11
|
+
File.join(internal_config_directory, 'default.yml')
|
12
|
+
end
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
::Rails.root
|
23
|
-
else
|
24
|
-
try_detect_capfile
|
25
|
-
end
|
26
|
-
end
|
14
|
+
def default_internal_config
|
15
|
+
@default_config ||= YAML.load_file(internal_config_file)['default_config']
|
16
|
+
@default_config
|
17
|
+
end
|
27
18
|
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
def find_env_multi_cap_root
|
20
|
+
ENV['MULTI_CAP_ROOT']
|
21
|
+
end
|
31
22
|
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
def root
|
24
|
+
File.expand_path(File.dirname(File.dirname(__dir__)))
|
25
|
+
end
|
35
26
|
|
36
|
-
|
37
|
-
|
38
|
-
|
27
|
+
def find_config_type(type)
|
28
|
+
['boolean'].include?(type.to_s) ? type.to_s.delete(':').to_sym : type.to_s.constantize
|
29
|
+
end
|
39
30
|
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
def try_detect_capfile
|
32
|
+
root = Pathname.new(FileUtils.pwd)
|
33
|
+
root = root.parent unless root.directory?
|
34
|
+
root = root.parent until root.children.find { |f| f.file? && f.basename.to_s.downcase == 'capfile' }.present? || root.root?
|
35
|
+
fail "Can't detect Capfile in the application root".red if root.root?
|
36
|
+
root
|
37
|
+
end
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
39
|
+
def app_debug_enabled?
|
40
|
+
app_configuration.multi_debug.to_s.downcase == 'true'
|
41
|
+
end
|
48
42
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
result = Ask.input message, default: default
|
53
|
-
$stdout.flush
|
54
|
-
`stty -raw echo`
|
55
|
-
return result
|
56
|
-
rescue
|
57
|
-
return nil
|
58
|
-
end
|
43
|
+
def show_warning(message)
|
44
|
+
warn message if app_debug_enabled?
|
45
|
+
end
|
59
46
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
class_name: message.class,
|
64
|
-
message: message.respond_to?(:message) ? message.message : message.inspect,
|
65
|
-
backtrace: message.respond_to?(:backtrace) ? message.backtrace.join("\n\n") : ''
|
66
|
-
)
|
67
|
-
end
|
47
|
+
def app_configuration
|
48
|
+
CapistranoMulticonfigParallel.configuration
|
49
|
+
end
|
68
50
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
51
|
+
def custom_commands
|
52
|
+
CapistranoMulticonfigParallel.custom_commands
|
53
|
+
end
|
54
|
+
|
55
|
+
def app_logger
|
56
|
+
CapistranoMulticonfigParallel.logger
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_terminal_tty
|
60
|
+
$stdin.sync = true if $stdin.isatty
|
61
|
+
$stdout.sync = true if $stdout.isatty
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_loaded_gem(name)
|
65
|
+
Gem.loaded_specs.values.find { |repo| repo.name == name }
|
66
|
+
end
|
67
|
+
|
68
|
+
def ask_confirm(message, default)
|
69
|
+
`stty -raw echo`
|
70
|
+
check_terminal_tty
|
71
|
+
result = Ask.input message, default: default
|
72
|
+
$stdout.flush
|
73
|
+
`stty -raw echo`
|
74
|
+
return result
|
75
|
+
rescue
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def log_error(message)
|
80
|
+
log_to_file(
|
81
|
+
class_name: message.class,
|
82
|
+
message: message.respond_to?(:message) ? message.message : message.inspect,
|
83
|
+
backtrace: message.respond_to?(:backtrace) ? message.backtrace.join("\n\n") : ''
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def log_to_file(message, job_id = nil)
|
88
|
+
worker_log = job_id.present? ? find_worker_log(job_id) : app_logger
|
89
|
+
worker_log.debug(message) if worker_log.present? && app_debug_enabled?
|
90
|
+
end
|
76
91
|
|
77
|
-
|
78
|
-
|
92
|
+
def find_worker_log(job_id)
|
93
|
+
return if job_id.blank?
|
94
|
+
FileUtils.mkdir_p(CapistranoMulticonfigParallel.log_directory) unless File.directory?(CapistranoMulticonfigParallel.log_directory)
|
95
|
+
filename = File.join(CapistranoMulticonfigParallel.log_directory, "worker_#{job_id}.log")
|
96
|
+
worker_log = ::Logger.new(filename)
|
97
|
+
worker_log.level = ::Logger::Severity::DEBUG
|
98
|
+
worker_log.formatter = proc do |severity, datetime, progname, msg|
|
99
|
+
date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
100
|
+
"[#{date_format}] #{severity} (#{progname}): #{msg}\n"
|
79
101
|
end
|
102
|
+
worker_log
|
80
103
|
end
|
81
104
|
end
|
82
105
|
end
|