bricolage 5.23.3 → 5.24.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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bricolage/application.rb +160 -37
  3. data/lib/bricolage/commandlineapplication.rb +0 -0
  4. data/lib/bricolage/commandutils.rb +0 -20
  5. data/lib/bricolage/context.rb +19 -4
  6. data/lib/bricolage/job.rb +38 -38
  7. data/lib/bricolage/jobfile.rb +2 -1
  8. data/lib/bricolage/jobnet.rb +21 -3
  9. data/lib/bricolage/jobnetrunner.rb +102 -62
  10. data/lib/bricolage/logfilepath.rb +2 -2
  11. data/lib/bricolage/loglocator.rb +71 -0
  12. data/lib/bricolage/loglocatorbuilder.rb +29 -0
  13. data/lib/bricolage/psqldatasource.rb +1 -1
  14. data/lib/bricolage/s3writer.rb +22 -0
  15. data/lib/bricolage/version.rb +1 -1
  16. data/test/home/Gemfile.lock +41 -0
  17. data/test/home/config/bricolage.yml +3 -0
  18. data/test/home/config/development/database.yml +113 -0
  19. data/test/home/config/development/password.yml +6 -0
  20. data/test/home/config/development/variable.yml +7 -0
  21. data/test/home/config/streamingload.yml +8 -0
  22. data/test/home/log/20170117/subsys::job1/20170117_202014082/subsys-job1.log +3 -0
  23. data/test/home/log/20170117/subsys::job1/20170117_202334852/subsys-job1.log +3 -0
  24. data/test/home/log/20170117/subsys::job1/20170117_202405056/subsys-job1.log +3 -0
  25. data/test/home/log/20170117/subsys::migrate/20170117_202548409/subsys-migrate.log +80 -0
  26. data/test/home/log/20170117/subsys::migrate/20170117_202636115/subsys-migrate.log +79 -0
  27. data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job1.log +3 -0
  28. data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job2.log +3 -0
  29. data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job3.log +3 -0
  30. data/test/home/log/20170117/subsys::net1/20170117_203022461/subsys-job4.log +3 -0
  31. data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job1.log +3 -0
  32. data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job2.log +3 -0
  33. data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job3.log +3 -0
  34. data/test/home/log/20170117/subsys::net1/20170117_203102130/subsys-job4.log +3 -0
  35. data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job1.log +3 -0
  36. data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job2.log +3 -0
  37. data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job3.log +3 -0
  38. data/test/home/log/20170117/subsys::net1/20170117_203232033/subsys-job4.log +3 -0
  39. data/test/home/log/20170629/subsys::job1/20170629_155543985/subsys-job1.log +3 -0
  40. data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job1.log +3 -0
  41. data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job2.log +3 -0
  42. data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job3.log +3 -0
  43. data/test/home/log/20170629/subsys::net1/20170629_154308811/subsys-job4.log +3 -0
  44. data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job1.log +3 -0
  45. data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job2.log +3 -0
  46. data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job3.log +3 -0
  47. data/test/home/log/20170629/subsys::net1/20170629_155330208/subsys-job4.log +3 -0
  48. data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job1.log +3 -0
  49. data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job2.log +3 -0
  50. data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job3.log +3 -0
  51. data/test/home/log/20170630/subsys::net1/20170630_145523511/subsys-job4.log +3 -0
  52. data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job1.log +3 -0
  53. data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job2.log +3 -0
  54. data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job3.log +3 -0
  55. data/test/home/log/20170630/subsys::net1/20170630_145545097/subsys-job4.log +3 -0
  56. data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job1.log +3 -0
  57. data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job2.log +3 -0
  58. data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job3.log +3 -0
  59. data/test/home/log/20170630/subsys::net1/20170630_145615702/subsys-job4.log +3 -0
  60. data/test/home/log/20170630/subsys::net1/20170630_153437221/subsys-job1.log +3 -0
  61. data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job1.log +3 -0
  62. data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job2.log +3 -0
  63. data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job3.log +3 -0
  64. data/test/home/log/20170630/subsys::net1/20170630_153507519/subsys-job4.log +3 -0
  65. data/test/home/log/20170704/subsys::insert.sql.job/20170704_163033119/subsys-insert.log +14 -0
  66. data/test/home/log/20170704/subsys::insert.sql.job/20170704_172410576/subsys-insert.log +14 -0
  67. data/test/home/log/20170704/subsys::insert.sql.job/20170704_173130175/subsys-insert.log +14 -0
  68. data/test/home/log/20170704/subsys::insert.sql.job/20170704_173201376/subsys-insert.log +14 -0
  69. data/test/home/log/20170704/subsys::insert.sql/20170704_164143661/subsys-insert.sql.log +14 -0
  70. data/test/home/log/20170704/subsys::insert/20170704_164335210/subsys-insert.log +14 -0
  71. data/test/home/log/20170704/subsys::insert/20170704_164344251/subsys-insert.log +14 -0
  72. data/test/home/log/20170704/subsys::insert/20170704_164723299/subsys-insert.log +14 -0
  73. data/test/home/log/20170704/subsys::net1/20170704_162457694/subsys-job1.log +3 -0
  74. data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job1.log +3 -0
  75. data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job2.log +3 -0
  76. data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job3.log +3 -0
  77. data/test/home/log/20170704/subsys::net1/20170704_162544282/subsys-job4.log +3 -0
  78. data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job1.log +3 -0
  79. data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job2.log +3 -0
  80. data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job3.log +3 -0
  81. data/test/home/log/20170706/subsys::net1/20170706_201157129/subsys-job4.log +3 -0
  82. data/test/home/log/20170707/subsys::insert/20170707_020050817/subsys-insert.log +51 -0
  83. data/test/home/log/20170707/subsys::insert/20170707_020050817/subsys-insert.log.status +1 -0
  84. data/test/home/log/20170707/subsys::job1/20170707_020542902/subsys-job1.log +3 -0
  85. data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job1.log +3 -0
  86. data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job2.log +3 -0
  87. data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job3.log +3 -0
  88. data/test/home/log/20170707/subsys::net1/20170707_012252058/subsys-job4.log +3 -0
  89. data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job1.log +3 -0
  90. data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job2.log +3 -0
  91. data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job3.log +3 -0
  92. data/test/home/log/20170707/subsys::net1/20170707_020039222/subsys-job4.log +3 -0
  93. data/test/home/revert.sh +7 -0
  94. data/test/home/s +1 -0
  95. metadata +125 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23ebf2fa74d99d152e388d57872332cd013fcd73
4
- data.tar.gz: 73a60961068be073e8833cd1d73769982e25b486
3
+ metadata.gz: f06abf75b09a7c9188d54ca938ccca52e8f122b5
4
+ data.tar.gz: 59c808715776490dc3374ef141528c3dc1d61960
5
5
  SHA512:
6
- metadata.gz: e7f1556d282e2ad26385bdb42c4133280208af22ab5098702384dda235a423ed15569dab1d596185654647e9e48db003191883229a092a1fd9c2f4bfc873631a
7
- data.tar.gz: 36b056529ae9ea99fd4318d30ef159a8b4dfd2b2936fb62e0987e81f620b9be5665a79c114f963a9fffb3bb460df894d52946ed4122e13cc13a4024434a992f5
6
+ metadata.gz: ee5d6895a71111e135885180841cc2c5518cf7fc822bdad0ea576c84a5f77fccade1a3f0f8d68ab3240c3e9cc4d21e01798c685f73e3e8fc114ed6997daf69e2
7
+ data.tar.gz: df04ca26661704bc676ee26afcbe1d9bc2940bfbd97bd8c70f42725ee4ccf5842046903620f1e87471ffd97bdbeec9059a8b61c42de0dda37142df9692d067cb
@@ -8,6 +8,7 @@ require 'bricolage/datasource'
8
8
  require 'bricolage/eventhandlers'
9
9
  require 'bricolage/postgresconnection'
10
10
  require 'bricolage/logfilepath'
11
+ require 'bricolage/loglocatorbuilder'
11
12
  require 'bricolage/logger'
12
13
  require 'bricolage/exception'
13
14
  require 'bricolage/version'
@@ -36,15 +37,26 @@ module Bricolage
36
37
  def main
37
38
  opts = GlobalOptions.new(self)
38
39
  @hooks.run_before_option_parsing_hooks(opts)
39
- opts.parse ARGV
40
+ opts.parse!(ARGV)
41
+
40
42
  @ctx = Context.for_application(opts.home, opts.job_file, environment: opts.environment, global_variables: opts.global_variables)
43
+ opts.merge_saved_options(@ctx.load_system_options)
44
+
45
+ if opts.dump_options?
46
+ opts.option_pairs.each do |name, value|
47
+ puts "#{name}=#{value.inspect}"
48
+ end
49
+ exit 0
50
+ end
41
51
  if opts.list_global_variables?
42
52
  list_variables @ctx.global_variables.resolve
43
53
  exit 0
44
54
  end
55
+
45
56
  job = load_job(@ctx, opts)
46
- process_job_options job, opts
57
+ process_job_options(job, opts)
47
58
  job.compile
59
+
48
60
  if opts.list_declarations?
49
61
  list_declarations job.declarations
50
62
  exit 0
@@ -62,11 +74,11 @@ module Bricolage
62
74
  exit 0
63
75
  end
64
76
 
77
+ @log_locator_builder = LogLocatorBuilder.for_options(@ctx, opts.log_path_format, opts.log_s3_ds, opts.log_s3_key_format)
78
+
65
79
  @hooks.run_before_all_jobs_hooks(BeforeAllJobsEvent.new(job.id, [job]))
66
80
  @hooks.run_before_job_hooks(BeforeJobEvent.new(job))
67
- result = redirect_log_to_file(opts.log_path, job) {
68
- job.execute
69
- }
81
+ result = job.execute(log_locator: build_log_locator(job))
70
82
  @hooks.run_after_job_hooks(AfterJobEvent.new(result))
71
83
  @hooks.run_after_all_jobs_hooks(AfterAllJobsEvent.new(result.success?, [job]))
72
84
  exit result.status
@@ -78,28 +90,13 @@ module Bricolage
78
90
  error_exit ex.message
79
91
  end
80
92
 
81
- def redirect_log_to_file(log_path, job)
82
- return yield unless log_path
83
-
84
- path = log_path.format(
93
+ def build_log_locator(job)
94
+ @log_locator_builder.build(
85
95
  job_ref: JobNet::JobRef.new(job.subsystem, job.id, '-'),
86
96
  jobnet_id: "#{job.subsystem}/#{job.id}",
87
97
  job_start_time: @start_time,
88
98
  jobnet_start_time: @start_time
89
99
  )
90
- FileUtils.mkdir_p File.dirname(path)
91
- stdout_save = $stdout.dup
92
- stderr_save = $stderr.dup
93
- begin
94
- File.open(path, 'w+') {|f|
95
- $stdout.reopen f
96
- $stderr.reopen f
97
- }
98
- return yield
99
- ensure
100
- $stdout.reopen stdout_save; stdout_save.close
101
- $stderr.reopen stderr_save; stderr_save.close
102
- end
103
100
  end
104
101
 
105
102
  def load_job(ctx, opts)
@@ -175,7 +172,124 @@ module Bricolage
175
172
  end
176
173
  end
177
174
 
178
- class GlobalOptions
175
+ class CommonApplicationOptions
176
+ OptionValue = Struct.new(:location, :value)
177
+ class OptionValue
178
+ def inspect
179
+ if location
180
+ "#{value.inspect} (#{location})"
181
+ else
182
+ value.inspect
183
+ end
184
+ end
185
+ end
186
+
187
+ def init_options
188
+ @opts = nil # valid only after #parse!
189
+ @opts_default = opts_default()
190
+ @opts_saved = {}
191
+ @opts_env = opts_env()
192
+ @opts_cmdline = {}
193
+ @parser = OptionParser.new
194
+ define_options @parser
195
+ end
196
+ private :init_options
197
+
198
+ attr_reader :parser
199
+
200
+ def opts_default
201
+ {
202
+ 'log-path' => OptionValue.new('default value', nil),
203
+ 'log-dir' => OptionValue.new('default value', nil),
204
+ 's3-log' => OptionValue.new('default value', nil)
205
+ }
206
+ end
207
+ private :opts_default
208
+
209
+ def opts_env
210
+ env = {}
211
+ if path = ENV['BRICOLAGE_LOG_PATH']
212
+ env['log-path'] = OptionValue.new('env BRICOLAGE_LOG_PATH', path)
213
+ end
214
+ if path = ENV['BRICOLAGE_LOG_DIR']
215
+ env['log-dir'] = OptionValue.new('env BRICOLAGE_LOG_DIR', path)
216
+ end
217
+ env
218
+ end
219
+ private :opts_env
220
+
221
+ # abstract :define_options
222
+
223
+ def define_common_options
224
+ @parser.on('-L', '--log-dir=PATH', 'Log file prefix.') {|path|
225
+ @opts_cmdline['log-dir'] = OptionValue.new('--log-dir option', path)
226
+ }
227
+ @parser.on('--log-path=PATH', 'Log file path template.') {|path|
228
+ @opts_cmdline['log-path'] = OptionValue.new('--log-path option', path)
229
+ }
230
+ @parser.on('--s3-log=DS_KEY', 'S3 log file. (format: "DS:KEY")') {|spec|
231
+ @opts_cmdline['s3-log'] = OptionValue.new('--s3-log option', spec)
232
+ }
233
+ end
234
+ private :define_common_options
235
+
236
+ def merge_saved_options(vars)
237
+ saved = {}
238
+ @opts_default.keys.each do |key|
239
+ if val = vars.get_force(key)
240
+ saved[key] = OptionValue.new("bricolage.yml:#{key}", val)
241
+ end
242
+ end
243
+ @opts_saved = saved
244
+ build_common_options!
245
+ end
246
+
247
+ def build_common_options!
248
+ @opts = [@opts_default, @opts_saved, @opts_env, @opts_cmdline].inject({}) {|h, opts| h.update(opts); h }
249
+ end
250
+ private :build_common_options!
251
+
252
+ #
253
+ # Accessors
254
+ #
255
+
256
+ def common_options
257
+ @opts
258
+ end
259
+
260
+ def log_path_format
261
+ if opt = @opts['log-dir']
262
+ LogFilePath.new("#{opt.value}/%{std}.log")
263
+ elsif opt = @opts['log-path']
264
+ LogFilePath.new(opt.value)
265
+ else
266
+ nil
267
+ end
268
+ end
269
+
270
+ def log_s3_ds
271
+ s3_log_spec.first
272
+ end
273
+
274
+ def log_s3_key_format
275
+ s3_log_spec.last
276
+ end
277
+
278
+ def s3_log_spec
279
+ @s3_log_spec ||=
280
+ if opt = @opts['s3-log']
281
+ spec = opt.value
282
+ ds, k = spec.split(':', 2)
283
+ k = k.to_s.strip
284
+ key = k.empty? ? nil : k
285
+ [ds, LogFilePath.new(key || '%{std}.log')]
286
+ else
287
+ [nil, nil]
288
+ end
289
+ end
290
+ end
291
+
292
+ class GlobalOptions < CommonApplicationOptions
179
293
  def initialize(app)
180
294
  @app = app
181
295
  @job_file = nil
@@ -184,16 +298,13 @@ module Bricolage
184
298
  @global_variables = Variables.new
185
299
  @dry_run = false
186
300
  @explain = false
187
- @log_path = LogFilePath.default
188
301
  @list_global_variables = false
189
302
  @list_variables = false
190
303
  @list_declarations = false
191
- @parser = OptionParser.new
192
- define_options @parser
304
+ @dump_options = false
305
+ init_options
193
306
  end
194
307
 
195
- attr_reader :parser
196
-
197
308
  def help
198
309
  @parser.help
199
310
  end
@@ -220,12 +331,9 @@ Global Options:
220
331
  parser.on('-E', '--explain', 'Applies EXPLAIN to the SQL.') {
221
332
  @explain = true
222
333
  }
223
- parser.on('-L', '--log-dir=PATH', 'Log file prefix.') {|path|
224
- @log_path = LogFilePath.new("#{path}/%{std}.log")
225
- }
226
- parser.on('--log-path=PATH', 'Log file path template.') {|path|
227
- @log_path = LogFilePath.new(path)
228
- }
334
+
335
+ define_common_options
336
+
229
337
  parser.on('--list-job-class', 'Lists job class name and (internal) class path.') {
230
338
  JobClass.list.each do |name|
231
339
  puts name
@@ -248,6 +356,9 @@ Global Options:
248
356
  name, value = name_value.split('=', 2)
249
357
  @global_variables[name] = value
250
358
  }
359
+ parser.on('--dump-options', 'Shows option parsing result and quit.') {
360
+ @dump_options = true
361
+ }
251
362
  parser.on('--help', 'Shows this message and quit.') {
252
363
  puts parser.help
253
364
  exit 0
@@ -262,19 +373,18 @@ Global Options:
262
373
  @parser.on(*args, &block)
263
374
  end
264
375
 
265
- def parse(argv)
376
+ def parse!(argv)
266
377
  @parser.order! argv
267
378
  @rest_args = argv.dup
379
+ build_common_options!
268
380
  rescue OptionParser::ParseError => ex
269
381
  raise OptionError, ex.message
270
382
  end
271
383
 
272
384
  attr_reader :environment
273
385
  attr_reader :home
274
- attr_reader :global_variables
275
386
 
276
387
  attr_reader :job_file
277
- attr_reader :log_path
278
388
 
279
389
  def file_mode?
280
390
  !!@job_file
@@ -288,6 +398,12 @@ Global Options:
288
398
  @explain
289
399
  end
290
400
 
401
+ def dump_options?
402
+ @dump_options
403
+ end
404
+
405
+ attr_reader :global_variables
406
+
291
407
  def list_global_variables?
292
408
  @list_global_variables
293
409
  end
@@ -299,6 +415,13 @@ Global Options:
299
415
  def list_declarations?
300
416
  @list_declarations
301
417
  end
418
+
419
+ def option_pairs
420
+ common_options.merge({
421
+ 'environment' => OptionValue.new(nil, @environment),
422
+ 'home' => OptionValue.new(nil, @home)
423
+ })
424
+ end
302
425
  end
303
426
 
304
427
  end
File without changes
@@ -27,26 +27,6 @@ module Bricolage
27
27
  def new_tmpfile_path(tmpdir = Dir.tmpdir)
28
28
  "#{tmpdir}/#{Time.now.to_i}_#{$$}_#{'%x' % Thread.current.object_id}_#{rand(2**16)}"
29
29
  end
30
-
31
- # CLUDGE: FIXME: bricolage-jobnet command writes stderr to the file, we can find error messages from there.
32
- # Using a temporary file or Ruby SQL driver is **MUCH** better.
33
- def retrieve_last_match_from_stderr(re, nth = 0)
34
- return unless $stderr.stat.file?
35
- $stderr.flush
36
- f = $stderr.dup
37
- matched = nil
38
- begin
39
- f.seek(0)
40
- f.each do |line|
41
- m = line.slice(re, nth)
42
- matched = m if m
43
- end
44
- ensure
45
- f.close
46
- end
47
- matched = matched.to_s.strip
48
- matched.empty? ? nil : matched
49
- end
50
30
  end
51
31
 
52
32
  end
@@ -84,6 +84,16 @@ module Bricolage
84
84
  :parameter_file,
85
85
  :parameter_file_loader
86
86
 
87
+ #
88
+ # System Parameters
89
+ #
90
+
91
+ SYSTEM_OPTION_FILE = 'bricolage.yml'
92
+
93
+ def load_system_options
94
+ load_variables_for_all_scopes(SYSTEM_OPTION_FILE)
95
+ end
96
+
87
97
  #
88
98
  # Variables
89
99
  #
@@ -103,15 +113,20 @@ module Bricolage
103
113
  }
104
114
  end
105
115
 
116
+ GLOBAL_VARIABLE_FILE = 'variable.yml'
117
+
106
118
  def load_global_variables
107
- subsys_path = scoped? ? [@filesystem.relative(GLOBAL_VARIABLE_FILE)] : []
108
- vars_list = (config_pathes(GLOBAL_VARIABLE_FILE) + subsys_path).map {|path|
119
+ load_variables_for_all_scopes(GLOBAL_VARIABLE_FILE)
120
+ end
121
+
122
+ def load_variables_for_all_scopes(basename)
123
+ subsys_path = scoped? ? [@filesystem.relative(basename)] : []
124
+ vars_list = (config_pathes(basename) + subsys_path).map {|path|
109
125
  path.exist? ? load_variables(path) : nil
110
126
  }
111
127
  Variables.union(*vars_list.compact)
112
128
  end
113
-
114
- GLOBAL_VARIABLE_FILE = 'variable.yml'
129
+ private :load_variables_for_all_scopes
115
130
 
116
131
  def load_variables(path)
117
132
  Variables.define {|vars|
data/lib/bricolage/job.rb CHANGED
@@ -55,7 +55,8 @@ module Bricolage
55
55
  end
56
56
 
57
57
  def init_global_variables
58
- # Context#global_variables loads file on each call, fix global variables here.
58
+ # Context#global_variables loads file on each call,
59
+ # updating @global_variables is multi-thread safe.
59
60
  @global_variables = @context.global_variables
60
61
  @global_variables['bricolage_cwd'] = Dir.pwd
61
62
  @global_variables['bricolage_job_dir'] = @context.job_dir.to_s
@@ -135,7 +136,26 @@ module Bricolage
135
136
  @script.run_explain
136
137
  end
137
138
 
138
- def execute
139
+ def execute(log_locator: LogLocator.empty)
140
+ log_locator.redirect_stdouts {
141
+ do_execute
142
+ }
143
+ end
144
+
145
+ def execute_in_process(log_locator:)
146
+ # ??? FIXME: status_path should be independent from log_path.
147
+ # Also, status_path should be defined regardless of log_path.
148
+ status_path = log_locator.path ? "#{log_locator.path}.status" : nil
149
+ isolate_process(status_path) {
150
+ log_locator.redirect_stdouts {
151
+ do_execute
152
+ }
153
+ }
154
+ end
155
+
156
+ private
157
+
158
+ def do_execute
139
159
  ENV['BRICOLAGE_PID'] = Process.pid.to_s
140
160
  logger = @context.logger
141
161
  logger.info "#{@context.environment} environment"
@@ -154,60 +174,40 @@ module Bricolage
154
174
  return JobResult.error(ex)
155
175
  end
156
176
 
157
- def execute_in_process(log_path)
158
- isolate(log_path) {
159
- execute
160
- }
161
- end
162
-
163
- private
164
-
165
- def isolate(log_path)
177
+ def isolate_process(status_path)
166
178
  cpid = Process.fork {
167
179
  Process.setproctitle "bricolage [#{@id}]"
168
- redirect_stdouts_to log_path if log_path
169
180
  result = yield
170
- save_result result, log_path
181
+ save_result result, status_path
171
182
  exit result.status
172
183
  }
173
184
  _, st = Process.waitpid2(cpid)
174
- restore_result(st, log_path)
175
- end
176
-
177
- def redirect_stdouts_to(path)
178
- FileUtils.mkdir_p File.dirname(path)
179
- # make readable for retrieve_last_match_from_stderr
180
- File.open(path, 'w+') {|f|
181
- $stdout.reopen f
182
- $stderr.reopen f
183
- }
185
+ restore_result(st, status_path)
184
186
  end
185
187
 
186
- def save_result(result, log_path)
188
+ def save_result(result, status_path)
187
189
  return if result.success?
188
- return unless log_path
190
+ return unless status_path
189
191
  begin
190
- File.open(error_log_path(log_path), 'w') {|f|
192
+ File.open(status_path, 'w') {|f|
191
193
  f.puts result.message
192
194
  }
193
195
  rescue
194
196
  end
195
197
  end
196
198
 
197
- def restore_result(st, log_path)
198
- JobResult.for_process_status(st, restore_message(log_path))
199
- end
200
-
201
- def restore_message(log_path)
202
- return nil unless log_path
203
- msg = read_if_exist(error_log_path(log_path))
204
- msg ? msg.strip : nil
205
- ensure
206
- FileUtils.rm_f error_log_path(log_path) if log_path
199
+ def restore_result(st, status_path)
200
+ JobResult.for_process_status(st, restore_message(status_path))
207
201
  end
208
202
 
209
- def error_log_path(log_path)
210
- "#{log_path}.error"
203
+ def restore_message(status_path)
204
+ return nil unless status_path
205
+ begin
206
+ msg = read_if_exist(status_path)
207
+ msg ? msg.strip : nil
208
+ ensure
209
+ FileUtils.rm_f status_path
210
+ end
211
211
  end
212
212
 
213
213
  def read_if_exist(path)