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
@@ -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