bricolage 5.23.3 → 5.24.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -90,7 +90,8 @@ module Bricolage
90
90
  attr_reader :path
91
91
 
92
92
  def job_id
93
- @path.basename('.job').to_s
93
+ base = @path.basename('.job').to_s
94
+ File.basename(base, '.*')
94
95
  end
95
96
 
96
97
  def subsystem
@@ -5,27 +5,45 @@ module Bricolage
5
5
 
6
6
  # Represents "first" jobnet given by command line (e.g. bricolage-jobnet some.jobnet)
7
7
  class RootJobNet
8
+ def RootJobNet.load_auto(ctx, path)
9
+ if path.extname == '.job'
10
+ load_single_job(ctx, path)
11
+ else
12
+ load(ctx, path)
13
+ end
14
+ end
15
+
8
16
  def RootJobNet.load(ctx, path)
9
- root = new(JobNet::FileLoader.new(ctx), JobNet.load(path))
17
+ root = new(JobNet::FileLoader.new(ctx), JobNet.load(path), path)
10
18
  root.load_recursive
11
19
  root.fix
12
20
  root
13
21
  end
14
22
 
15
23
  def RootJobNet.load_single_job(ctx, path)
16
- root = new(JobNet::FileLoader.new(ctx), JobNet.load_single_job(path))
24
+ root = new(JobNet::FileLoader.new(ctx), JobNet.load_single_job(path), path)
17
25
  root.load_recursive
18
26
  root.fix
19
27
  root
20
28
  end
21
29
 
22
- def initialize(jobnet_loader, start_jobnet)
30
+ def initialize(jobnet_loader, start_jobnet, path = nil)
23
31
  @jobnet_loader = jobnet_loader
24
32
  @start_jobnet = start_jobnet
33
+ @path = path
25
34
  @jobnets = {start_jobnet.ref => start_jobnet}
26
35
  @graph = nil
27
36
  end
28
37
 
38
+ def id
39
+ return nil unless @path
40
+ @id ||= begin
41
+ subsys = @path.dirname.basename
42
+ base = @path.basename.to_s.sub(/\..*\z/, '')
43
+ "#{subsys}/#{base}"
44
+ end
45
+ end
46
+
29
47
  attr_reader :start_jobnet
30
48
 
31
49
  def each_jobnet(&block)
@@ -8,6 +8,7 @@ require 'bricolage/datasource'
8
8
  require 'bricolage/variables'
9
9
  require 'bricolage/eventhandlers'
10
10
  require 'bricolage/logfilepath'
11
+ require 'bricolage/loglocatorbuilder'
11
12
  require 'bricolage/logger'
12
13
  require 'bricolage/exception'
13
14
  require 'bricolage/version'
@@ -26,8 +27,6 @@ module Bricolage
26
27
  @hooks = ::Bricolage
27
28
  @jobnet_id = nil
28
29
  @jobnet_start_time = Time.now
29
- @job_start_time = nil
30
- @log_path = nil
31
30
  end
32
31
 
33
32
  EXIT_SUCCESS = JobResult::EXIT_SUCCESS
@@ -37,24 +36,31 @@ module Bricolage
37
36
  def main
38
37
  opts = Options.new(self)
39
38
  @hooks.run_before_option_parsing_hooks(opts)
40
- opts.parse ARGV
39
+ opts.parse!(ARGV)
40
+
41
41
  @ctx = Context.for_application(job_path: opts.jobnet_file, environment: opts.environment, global_variables: opts.global_variables)
42
- @jobnet_id = "#{opts.jobnet_file.dirname.basename}/#{opts.jobnet_file.basename('.jobnet')}"
43
- @log_path = opts.log_path
44
- jobnet =
45
- if opts.jobnet_file.extname == '.job'
46
- RootJobNet.load_single_job(@ctx, opts.jobnet_file)
47
- else
48
- RootJobNet.load(@ctx, opts.jobnet_file)
42
+ opts.merge_saved_options(@ctx.load_system_options)
43
+
44
+ jobnet = RootJobNet.load_auto(@ctx, opts.jobnet_file)
45
+ @jobnet_id = jobnet.id
46
+
47
+ if opts.dump_options?
48
+ puts "jobnet-id=#{@jobnet_id}"
49
+ puts "jobnet-file=#{opts.jobnet_file}"
50
+ opts.option_pairs.each do |key, value|
51
+ puts "#{key}=#{value.inspect}"
49
52
  end
53
+ exit EXIT_SUCCESS
54
+ end
55
+
50
56
  queue = get_queue(opts)
51
57
  if queue.locked?
52
58
  raise ParameterError, "Job queue is still locked. If you are sure to restart jobnet, #{queue.unlock_help}"
53
59
  end
54
60
  unless queue.queued?
55
61
  enqueue_jobs jobnet, queue
56
- logger.info "jobs are queued."
57
62
  end
63
+
58
64
  if opts.list_jobs?
59
65
  list_jobs queue
60
66
  exit EXIT_SUCCESS
@@ -64,6 +70,8 @@ module Bricolage
64
70
  puts "OK"
65
71
  exit EXIT_SUCCESS
66
72
  end
73
+
74
+ @log_locator_builder = LogLocatorBuilder.for_options(@ctx, opts.log_path_format, opts.log_s3_ds, opts.log_s3_key_format)
67
75
  run_queue queue
68
76
  exit EXIT_SUCCESS
69
77
  rescue OptionError => ex
@@ -144,11 +152,11 @@ module Bricolage
144
152
 
145
153
  def execute_job(ref, queue)
146
154
  logger.debug "job #{ref}"
147
- @job_start_time = Time.now
155
+ job_start_time = Time.now
148
156
  job = Job.load_ref(ref, @ctx)
149
157
  job.compile
150
158
  @hooks.run_before_job_hooks(BeforeJobEvent.new(ref))
151
- result = job.execute_in_process(instanciate_log_path(ref))
159
+ result = job.execute_in_process(log_locator: make_log_locator(ref, job_start_time))
152
160
  @hooks.run_after_job_hooks(AfterJobEvent.new(result))
153
161
  result
154
162
  rescue Exception => ex
@@ -157,12 +165,11 @@ module Bricolage
157
165
  JobResult.error(ex)
158
166
  end
159
167
 
160
- def instanciate_log_path(ref)
161
- return nil unless @log_path
162
- @log_path.format(
168
+ def make_log_locator(ref, job_start_time)
169
+ @log_locator_builder.build(
163
170
  job_ref: ref,
164
171
  jobnet_id: @jobnet_id,
165
- job_start_time: @job_start_time,
172
+ job_start_time: job_start_time,
166
173
  jobnet_start_time: @jobnet_start_time
167
174
  )
168
175
  end
@@ -189,51 +196,40 @@ module Bricolage
189
196
  File.basename($PROGRAM_NAME, '.*')
190
197
  end
191
198
 
192
- class Options
199
+ class Options < CommonApplicationOptions
193
200
  def initialize(app)
194
201
  @app = app
195
202
  @environment = nil
203
+ @global_variables = Variables.new
196
204
  @jobnet_files = nil
197
- @log_path = LogFilePath.default
198
- @local_state_dir = Pathname('/tmp/bricolage')
199
- if path = ENV['BRICOLAGE_QUEUE_PATH']
200
- @enable_queue = true
201
- @queue_path = Pathname(path)
202
- elsif ENV['BRICOLAGE_ENABLE_QUEUE']
203
- @enable_queue = true
204
- @queue_path = nil
205
- else
206
- @enable_queue = false
207
- @queue_path = nil
208
- end
205
+
206
+ @dump_options = false
209
207
  @check_only = false
210
208
  @list_jobs = false
211
- @global_variables = Variables.new
212
- @parser = OptionParser.new
213
- define_options @parser
214
- end
215
209
 
216
- attr_reader :environment
217
- attr_reader :jobnet_file
218
- attr_reader :log_path
219
-
220
- attr_reader :local_state_dir
221
-
222
- def enable_queue?
223
- @enable_queue
210
+ init_options
224
211
  end
225
212
 
226
- attr_reader :queue_path
227
-
228
- def check_only?
229
- @check_only
213
+ def opts_default
214
+ super.merge({
215
+ 'local-state-dir' => OptionValue.new('default value', nil),
216
+ 'enable-queue' => OptionValue.new('default value', false),
217
+ 'queue-path' => OptionValue.new('default value', '/tmp/bricolage')
218
+ })
230
219
  end
220
+ private :opts_default
231
221
 
232
- def list_jobs?
233
- @list_jobs
222
+ def opts_env
223
+ env = super
224
+ if ENV['BRICOLAGE_ENABLE_QUEUE']
225
+ env['enable-queue'] = OptionValue.new('env BRICOLAGE_ENABLE_QUEUE', true)
226
+ end
227
+ if path = ENV['BRICOLAGE_QUEUE_PATH']
228
+ env['queue-path'] = OptionValue.new('env BRICOLAGE_QUEUE_PATH', path)
229
+ end
230
+ env
234
231
  end
235
-
236
- attr_reader :global_variables
232
+ private :opts_env
237
233
 
238
234
  def help
239
235
  @parser.help
@@ -248,20 +244,17 @@ Options:
248
244
  parser.on('-e', '--environment=NAME', "Sets execution environment. [default: #{Context::DEFAULT_ENV}]") {|env|
249
245
  @environment = env
250
246
  }
251
- parser.on('-L', '--log-dir=PATH', 'Log file prefix.') {|path|
252
- @log_path = LogFilePath.new("#{path}/%{std}.log")
253
- }
254
- parser.on('--log-path=PATH', 'Log file path template.') {|path|
255
- @log_path = LogFilePath.new(path)
256
- }
247
+
248
+ define_common_options
249
+
257
250
  parser.on('--local-state-dir=PATH', 'Stores local state in this path.') {|path|
258
- @local_state_dir = Pathname(path)
251
+ @opts_cmdline['local-state-dir'] = OptionValue.new('--local-state-dir option', path)
259
252
  }
260
253
  parser.on('-Q', '--enable-queue', 'Enables job queue.') {
261
- @enable_queue = true
254
+ @opts_cmdline['enable-queue'] = OptionValue.new('--enable-queue option', true)
262
255
  }
263
256
  parser.on('--queue-path=PATH', 'Enables job queue with this path.') {|path|
264
- @queue_path = Pathname(path)
257
+ @opts_cmdline['queue-path'] = OptionValue.new('--queue-path option', path)
265
258
  }
266
259
  parser.on('-c', '--check-only', 'Checks job parameters and quit without executing.') {
267
260
  @check_only = true
@@ -273,6 +266,9 @@ Options:
273
266
  name, value = name_value.split('=', 2)
274
267
  @global_variables[name] = value
275
268
  }
269
+ parser.on('--dump-options', 'Shows option parsing result and quit.') {
270
+ @dump_options = true
271
+ }
276
272
  parser.on('--help', 'Shows this message and quit.') {
277
273
  @app.puts parser.help
278
274
  @app.exit 0
@@ -287,14 +283,58 @@ Options:
287
283
  @parser.on(*args, &block)
288
284
  end
289
285
 
290
- def parse(argv)
291
- @parser.parse! argv
286
+ def parse!(argv)
287
+ @parser.parse!(argv)
292
288
  raise OptionError, "missing jobnet file" if argv.empty?
293
289
  raise OptionError, "too many jobnet file" if argv.size > 1
294
- @jobnet_file = argv.map {|path| Pathname(path) }.first
290
+ @jobnet_file = Pathname(argv.first)
291
+ build_common_options!
295
292
  rescue OptionParser::ParseError => ex
296
293
  raise OptionError, ex.message
297
294
  end
295
+
296
+ attr_reader :environment
297
+ attr_reader :jobnet_file
298
+
299
+ attr_reader :global_variables
300
+
301
+ def dump_options?
302
+ @dump_options
303
+ end
304
+
305
+ def check_only?
306
+ @check_only
307
+ end
308
+
309
+ def list_jobs?
310
+ @list_jobs
311
+ end
312
+
313
+ def local_state_dir
314
+ @local_state_dir ||= begin
315
+ opt = @opts['local-state-dir']
316
+ Pathname(opt.value)
317
+ end
318
+ end
319
+
320
+ def enable_queue?
321
+ opt = @opts['enable-queue']
322
+ opt.value
323
+ end
324
+
325
+ def queue_path
326
+ if opt = @opts['queue-path']
327
+ Pathname(opt.value)
328
+ else
329
+ nil
330
+ end
331
+ end
332
+
333
+ def option_pairs
334
+ common_options.merge({
335
+ 'environment' => OptionValue.new(nil, @environment)
336
+ })
337
+ end
298
338
  end
299
339
  end
300
340
 
@@ -14,14 +14,14 @@ module Bricolage
14
14
  @template = template
15
15
  end
16
16
 
17
- Params = Struct.new(:job_ref, :jobnet_id, :job_start_time, :jobnet_start_time)
18
-
19
17
  def format(job_ref:, jobnet_id:, job_start_time:, jobnet_start_time:)
20
18
  return nil unless @template
21
19
  params = Params.new(job_ref, jobnet_id, job_start_time, jobnet_start_time)
22
20
  fill_template(@template, params)
23
21
  end
24
22
 
23
+ Params = Struct.new(:job_ref, :jobnet_id, :job_start_time, :jobnet_start_time)
24
+
25
25
  def fill_template(template, params)
26
26
  template.gsub(/%\{\w+\}/) {|var|
27
27
  case var
@@ -0,0 +1,71 @@
1
+ module Bricolage
2
+ class LogLocator
3
+ def LogLocator.empty
4
+ new(nil, nil)
5
+ end
6
+
7
+ def initialize(path, s3_writer)
8
+ @path = path
9
+ @s3_writer = s3_writer
10
+ end
11
+
12
+ attr_reader :path
13
+
14
+ def s3_url
15
+ return nil unless @s3_writer
16
+ @s3_writer.url
17
+ end
18
+
19
+ def redirect_stdouts
20
+ return yield unless @path
21
+ FileUtils.mkdir_p File.dirname(@path)
22
+ @original_stdout = $stdout.dup
23
+ @original_stderr = $stderr.dup
24
+ begin
25
+ # Use 'w+' to make readable for retrieve_last_match_from_stderr
26
+ File.open(@path, 'w+') {|f|
27
+ f.sync = true
28
+ $stdout.reopen f
29
+ $stderr.reopen f
30
+ }
31
+ return yield
32
+ ensure
33
+ $stdout.reopen @original_stdout; @original_stdout.close
34
+ $stderr.reopen @original_stderr; @original_stderr.close
35
+ upload
36
+ end
37
+ end
38
+
39
+ # CLUDGE: FIXME: We redirect stderr to the file, we can find error messages from there.
40
+ # Using a temporary file or Ruby SQL driver is **MUCH** better.
41
+ def self.slice_last_stderr(re, nth = 0)
42
+ return unless $stderr.stat.file?
43
+ $stderr.flush
44
+ f = $stderr.dup
45
+ matched = nil
46
+ begin
47
+ f.seek(0)
48
+ f.each do |line|
49
+ m = line.slice(re, nth)
50
+ matched = m if m
51
+ end
52
+ ensure
53
+ f.close
54
+ end
55
+ matched = matched.to_s.strip
56
+ matched.empty? ? nil : matched
57
+ end
58
+
59
+ def upload
60
+ return unless @path
61
+ return unless @s3_writer
62
+ # FIXME: Shows HTTP URL?
63
+ puts "bricolage: S3 log: #{s3_url}"
64
+ begin
65
+ @s3_writer.upload(path)
66
+ rescue => ex
67
+ puts "warning: S3 upload failed: #{s3_url}"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,29 @@
1
+ require 'bricolage/loglocator'
2
+ require 'bricolage/s3writer'
3
+
4
+ module Bricolage
5
+ class LogLocatorBuilder
6
+ def LogLocatorBuilder.for_options(ctx, log_path_format, s3_ds, s3_key_format)
7
+ ds = s3_ds ? ctx.get_data_source('s3', s3_ds) : nil
8
+ new(log_path_format, ds, s3_key_format)
9
+ end
10
+
11
+ def initialize(log_path_format, s3_ds, s3_key_format)
12
+ @log_path_format = log_path_format
13
+ @s3_ds = s3_ds
14
+ @s3_key_format = s3_key_format
15
+ end
16
+
17
+ def build(**params)
18
+ path = @log_path_format ? @log_path_format.format(**params) : nil
19
+ s3_writer =
20
+ if @s3_ds and @s3_key_format
21
+ key = @s3_key_format.format(**params)
22
+ S3Writer.new(@s3_ds, key)
23
+ else
24
+ nil
25
+ end
26
+ LogLocator.new(path, s3_writer)
27
+ end
28
+ end
29
+ end
@@ -71,7 +71,7 @@ module Bricolage
71
71
  '--no-password',
72
72
  *options,
73
73
  env: get_psql_env
74
- msg = retrieve_last_match_from_stderr(/^psql:.*?:\d+: ERROR: (.*)/, 1) unless st.success?
74
+ msg = LogLocator.slice_last_stderr(/^psql:.*?:\d+: ERROR: (.*)/, 1) unless st.success?
75
75
  JobResult.for_process_status(st, msg)
76
76
  }
77
77
  end