capistrano_multiconfig_parallel 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|