metababel 0.1.0 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f9cdd491e69bf7414791f771ed3902bb4d8ba27dd28c6b2e66bb677662a6c9d
4
- data.tar.gz: 13c2e7c0c201b9a3f51d55e8ea9438284f77285ad6f8c640f20567c88e5f6f88
3
+ metadata.gz: 8622843bd93dc9b0e2ed91f3ad7bb444ea2216ba183651d17773de232749a187
4
+ data.tar.gz: 762a87b56229cee6bebe99ebb5358610672a6fb2a171718c3255ad079391ba85
5
5
  SHA512:
6
- metadata.gz: a908872fc837088e86f43aa08ca113795287c35a3d249c140295c9471089cc418b8ff8cab7dc7817acb0193df5d42c2fd51d191cd63ef1d22539b0428d2c5180
7
- data.tar.gz: e7d44bcafe7a4be48336a5da021f911b31db8877d06b7d7c6c3918ee520adbd51093567d9a502a6a52395b490d306b04ede726be97dceaea7b8e2b6276025993
6
+ metadata.gz: 0fbe1685dafbc6d45e03a494607efa1010cde5973167f394150322b36d784eb23305664b8adea0ef12d90c0552a61d726cb1fce83620211f8827c1e4101f0ee0
7
+ data.tar.gz: cb578b9f45359fd1a93d219761f41ecdb0e0670150be69c731f4d5c1c2695e3ade918e2b5e825701cff380dcaaad6f76c09638628664f3d879f009191e9f9b58
data/README.md CHANGED
@@ -57,4 +57,16 @@ stateDiagram-v2
57
57
 
58
58
  At finalization we will call the `btx_user_finalization(struct xprof_common_data *common_data)`
59
59
 
60
-
60
+ # Callbacks Registration and Calling order
61
+
62
+ ```
63
+ 0 register_callback
64
+ 1 call_initialize_component # Cannot Push
65
+ 2 call_read_params
66
+ 3 stream_begin
67
+ 4 call_initialize_processing # Can Push
68
+ 5 call_callbacks
69
+ 5 call_finalize_processing # Can Push
70
+ 6 stream_end
71
+ 7 call_finalize_component # Cannot push
72
+ ```
data/bin/metababel CHANGED
@@ -5,19 +5,8 @@ require 'optparse'
5
5
  require 'erb'
6
6
  require 'metababel'
7
7
  require 'fileutils'
8
-
9
- def validate_model(yaml)
10
- # Stream and event classes must have a 'name' as minimum requirement.
11
- raise "Missing 'name' attr in model #{yaml}" unless yaml[:stream_classes].all? do |d|
12
- d.key?(:name) && d[:event_classes].all? do |d2|
13
- d2.key?(:name)
14
- end
15
- end
16
-
17
- # Event class name must be unique
18
- events = yaml[:stream_classes].flat_map { |sc| sc[:event_classes] }.map { |e| e[:name] }
19
- raise "Duplicated 'event' in model #{yaml}" unless events.length == events.uniq.length
20
- end
8
+ require 'set'
9
+ require 'ostruct'
21
10
 
22
11
  class Array
23
12
  def join_with_prefix(sep)
@@ -44,19 +33,113 @@ class Hash
44
33
  end
45
34
  end
46
35
 
47
- EventClassInfo = Struct.new(:name, :args, :body, :index_stream_class, :index_event_class, :default_clock_class,
48
- :args_to_free) do
49
- def name_sanitized
50
- name.gsub(/[^0-9A-Za-z-]/, '_')
36
+ class Babeltrace2Gen::BTTraceClass
37
+ def filter_map_event_classes_with_index
38
+ @stream_classes.map.with_index do |s, index_stream_class|
39
+ s.event_classes.filter_map.with_index do |e, index_event_class|
40
+ yield(e, index_stream_class, index_event_class, s.default_clock_class)
41
+ end
42
+ end.flatten(1)
51
43
  end
52
44
  end
53
45
 
54
- StreamClassInfo = Struct.new(:name, :args, :body, :default_clock_class) do
46
+ def sanitize(str)
47
+ str.gsub(/[^0-9A-Za-z-]/, '_')
48
+ end
49
+
50
+ class BaseDispatch
55
51
  def name_sanitized
56
- name.gsub(/[^0-9A-Za-z-]/, '_')
52
+ sanitize(@name)
53
+ end
54
+
55
+ # https://ruby-doc.org/3.2.2/Hash.html#class-Hash-label-User-Defined+Hash+Keys
56
+ def ==(other)
57
+ self.class === other and
58
+ instance_variables.all? { |s| instance_variable_get(s) == other.instance_variable_get(s) }
59
+ end
60
+
61
+ alias eql? ==
62
+
63
+ def hash
64
+ instance_variables.reduce(0) { |a, b| a ^ instance_variable_get(b).hash }
65
+ end
66
+ end
67
+
68
+ class StaticDispatcher < BaseDispatch
69
+ attr_reader :name, :args, :no_btx_handle
70
+
71
+ def initialize(name, args, no_btx_handle: false)
72
+ @name = name
73
+ @args = args
74
+ @no_btx_handle = no_btx_handle
75
+ end
76
+ end
77
+
78
+ class DispatchType < BaseDispatch
79
+ attr_reader :name, :args, :id, :matched_dispatchers
80
+
81
+ def initialize(name, args, id, matched_dispatchers)
82
+ @name = name
83
+ @args = args
84
+ @id = id
85
+ @matched_dispatchers = matched_dispatchers
86
+ end
87
+ end
88
+
89
+ class Dispatcher < BaseDispatch
90
+ attr_reader :event_nane, :event, :name,
91
+ :index_stream_class, :index_event_class,
92
+ :default_clock_class,
93
+ :dispatch_types
94
+
95
+ def initialize(event, event_name,
96
+ mode,
97
+ index_stream_class, index_event_class, default_clock_class)
98
+ @event = event
99
+ @event_name = event_name
100
+ @mode = mode
101
+ @index_stream_class = index_stream_class
102
+ @index_event_class = index_event_class
103
+ @default_clock_class = default_clock_class
104
+ @dispatch_types = []
105
+ @name = event.name
106
+ end
107
+
108
+ def body_args
109
+ @body_args ||= begin
110
+ arg_variables = {}
111
+ body = Babeltrace2Gen.context(indent: 1) do
112
+ if @mode == 'setter'
113
+ @event.get_setter(event: @event_name, arg_variables: arg_variables)
114
+ elsif @mode == 'getter'
115
+ @event.get_getter(event: @event_name, arg_variables: arg_variables)
116
+ end
117
+ end
118
+ [arg_variables, body]
119
+ end
120
+ end
121
+
122
+ # We preprent an empty new line from the body as a hack, to correct the indentation
123
+ # Indeeed the <%= body %> will be indented, but we don't don't want it,
124
+ # in the body string is already indented
125
+ # But we clean the white space empty line afterward \o/
126
+ def body
127
+ "\n" + body_args[1]
128
+ end
129
+
130
+ def args
131
+ evt_args = []
132
+ evt_args += [GeneratedArg.new('int64_t', '_timestamp')] if @default_clock_class
133
+ evt_args += body_args[0].fetch('outputs', [])
134
+ end
135
+
136
+ def args_to_free
137
+ body_args[0].fetch('outputs_allocated', [])
57
138
  end
58
139
  end
59
140
 
141
+ GeneratedArg = Struct.new(:type, :name)
142
+
60
143
  def erb_render_and_save(vars,
61
144
  basename, out_folder, out_name: nil, prefix: 'btx_')
62
145
  template = File.read(File.join(__dir__, "../template/#{basename}.erb"))
@@ -65,202 +148,334 @@ def erb_render_and_save(vars,
65
148
  # The regex remove the lines who are not indented
66
149
  # Maybe related to `https://github.com/ruby/erb/issues/24`
67
150
  str = ERB.new(template, trim_mode: '<>').result_with_hash(vars).gsub(/^ +$\n/, '')
68
- File.open(File.join(out_folder, "#{prefix}#{out_name || basename}"), 'w') do |f|
69
- f.write(str)
70
- end
151
+ File.write(File.join(out_folder, "#{prefix}#{out_name || basename}"), str)
71
152
  end
72
153
 
73
- class Babeltrace2Gen::BTTraceClass
74
- def map_event_classes_with_index
75
- @stream_classes.map.with_index do |s, index_stream_class|
76
- s.event_classes.map.with_index do |e, index_event_class|
77
- yield(e, index_stream_class, index_event_class, s.default_clock_class)
78
- end
79
- end.flatten
80
- end
81
- end
154
+ def parse_argv
155
+ # Display help if no arguments.
156
+ ARGV << '-h' if ARGV.empty?
82
157
 
83
- class GeneratedArg < Struct.new(:type, :name)
84
- end
158
+ options = {}
159
+
160
+ options[:disable_callbaks] = ['on_downstream'].to_set
85
161
 
86
- # We preprent an empty new line from the body as a hack, to correct the indentation
87
- # Indeeed the <%= body %> will be indented, but we don't don't want it,
88
- # in the body string is already indented
89
- # But we clean the white space empty line afterward \o/
90
- def wrote_event_dispatchers(folder, t)
91
- event_name = 'event'
92
- event_class_dispatchers = t.map_event_classes_with_index do |e, index_stream_class, index_event_class, default_clock_class|
93
- arg_variables = {}
94
- body = Babeltrace2Gen.context(indent: 1) do
95
- e.get_getter(event: event_name, arg_variables: arg_variables)
162
+ OptionParser.new do |opts|
163
+ opts.banner = 'Usage: example.rb [options]'
164
+
165
+ opts.on('-h', '--help', 'Prints this help') do
166
+ puts opts
167
+ exit
96
168
  end
97
- EventClassInfo.new(e.name, arg_variables.fetch('outputs', []), body, index_stream_class, index_event_class, default_clock_class,
98
- arg_variables.fetch('outputs_allocated', []))
99
- end
100
169
 
101
- stream_classes_matching_dispatchers = t.stream_classes.map do |s|
102
- arg_variables = {}
103
- body = ''
104
- if s.event_common_context_field_class
105
- body = Babeltrace2Gen.context(indent: 1) do
106
- s.get_getter(event: event_name, arg_variables: arg_variables)
107
- end
170
+ opts.on('-v', '--version', 'Prints this help') do
171
+ puts "Ruby: #{RUBY_VERSION}"
172
+ puts "Metababel: #{Metababel::VERSION}"
173
+ exit
108
174
  end
109
- StreamClassInfo.new(s.name, arg_variables.fetch('outputs', []), body, s.default_clock_class)
110
- end
111
175
 
112
- d = { event_class_dispatchers: event_class_dispatchers,
113
- stream_classes_matching_dispatchers: stream_classes_matching_dispatchers,
114
- event_name: event_name }
176
+ opts.on('-t', '--component TYPE', '[Mandatory] Node within a trace processing graph.') do |p|
177
+ options[:component_type] = p
178
+ end
115
179
 
116
- erb_render_and_save(d, 'upstream.h', folder)
117
- erb_render_and_save(d, 'upstream.c', folder)
118
- end
180
+ opts.on('-u', '--upstreams PATH', Array, '[Mandatory] Path to the bt2 YAML files for the upstream model.') do |p|
181
+ options[:upstreams] = p
182
+ end
183
+
184
+ opts.on('-d', '--downstream PATH', '[Optional] Path to the bt2 YAML file for the downstream model.') do |p|
185
+ options[:downstream] = p
186
+ end
187
+
188
+ opts.on('-p', '--plugin-name PATH', '[Optional] Name of the bt2 plugin created.') do |p|
189
+ options[:plugin_name] = p
190
+ end
191
+
192
+ opts.on('-c', '--component-name PATH', '[Optional] Name of the bt2 componant created.') do |p|
193
+ options[:component_name] = p
194
+ end
195
+
196
+ opts.on('--params PATH', '[Optional] Paht to the bt2 YAML params definition.') do |p|
197
+ options[:params] = p
198
+ end
199
+
200
+ opts.on('-m', '--matching PATH', '[Optional] Path to bt2 YAML matching-callbacks definitions.') do |p|
201
+ options[:matching] = p
202
+ end
203
+
204
+ opts.on('-o', '--output FOLDER', '[Optional] Output folder path.') do |p|
205
+ options[:folder] = p
206
+ end
207
+
208
+ opts.on('-i', '--usr-data-header NAME', '[Optional] User datatypes definitions.') do |p|
209
+ options[:usr_data_header] = p
210
+ end
119
211
 
120
- def wrote_creates(folder, t)
121
- event_name = 'event'
122
- downstream_events = t.map_event_classes_with_index do |e, index_stream_class, index_event_class, default_clock_class|
123
- arg_variables = {}
124
- body = Babeltrace2Gen.context(indent: 1) do
125
- e.get_setter(event: event_name, arg_variables: arg_variables)
212
+ opts.on('--enable-callbacks NAME', Array, '[Optional] Enable some callbacks type') do |p|
213
+ options[:disable_callbaks] -= p.to_set
126
214
  end
127
- EventClassInfo.new(e.name, arg_variables.fetch('outputs', []), "\n" + body, index_stream_class, index_event_class,
128
- default_clock_class)
215
+
216
+ end.parse!
217
+
218
+ raise OptionParser::MissingArgument if options[:component_type].nil?
219
+
220
+ options[:plugin_name] ||= "metababel_#{options[:component_type].downcase}"
221
+ options[:component_name] ||= 'btx'
222
+
223
+ options
224
+ end
225
+
226
+ def get_dispatch_type(em, default_clock_class, context)
227
+ dispatchers = em.domain ? OpenStruct.new(context).instance_eval(em.domain) : context['all']
228
+ raise "Nil or empty event set for '#{em.set_id}'." unless dispatchers.is_a?(Set)
229
+
230
+ matched_dispatchers, signatures = dispatchers.filter_map do |dispatcher|
231
+ extracted_args = dispatcher.event.match?(em)
232
+ [dispatcher, extracted_args] if extracted_args
233
+ end.transpose
234
+
235
+ if !matched_dispatchers || matched_dispatchers.empty?
236
+ raise "No event matched '#{em.set_id}', at least one matching event required."
129
237
  end
130
238
 
131
- body_declarator_classes = "\n" + Babeltrace2Gen.context(indent: 1) do
132
- t.get_declarator(variable: 'trace_class', self_component: 'self_component')
239
+ # Verify the uniqueness of signatures.
240
+ # Note that `s.type` takes into account the `cast_type`
241
+ # (see TestMatchingConflictingSignatures for more details)
242
+ unique_signatures = signatures.uniq
243
+ unless unique_signatures.size == 1
244
+ signatures_str = unique_signatures.map { |s| "(#{s.map(&:type).join(', ')})" }.join(', ')
245
+ raise "Conflicting signatures for '#{em.set_id}', found #{unique_signatures.size} signatures, only one allowed: '#{signatures_str}'"
133
246
  end
134
247
 
135
- d = { body_declarator_classes: body_declarator_classes,
136
- downstream_events: downstream_events,
137
- stream_classes: t.stream_classes,
138
- event_name: event_name }
248
+ # Modify the dispatcher to add the new dispatchType
249
+ name = em.set_id
250
+ dispatch_type_args = []
251
+ dispatch_type_args += [GeneratedArg.new('int64_t', '_timestamp')] if default_clock_class
252
+ dispatch_type_args += [GeneratedArg.new('const char *', '_event_class_name')]
253
+ dispatch_type_args += signatures.pop
254
+
255
+ dispatch_type = DispatchType.new(
256
+ name, dispatch_type_args, "matching_#{sanitize(name)}", matched_dispatchers
257
+ )
258
+
259
+ # Update context for further events filtering.
260
+ context[dispatch_type.name] = dispatch_type.matched_dispatchers.to_set
261
+
262
+ # Exclude unnecessary rendering.
263
+ return false unless em.register
139
264
 
140
- erb_render_and_save(d, 'downstream.h', folder)
141
- erb_render_and_save(d, 'downstream.c', folder)
265
+ matched_dispatchers.each { |dispatcher| dispatcher.dispatch_types << dispatch_type }
266
+
267
+ dispatch_type
142
268
  end
143
269
 
144
- def wrote_component(options, d, folder)
145
- component_dispatchers = [EventClassInfo.new('initialize_usr_data',
146
- [GeneratedArg.new('void **', 'usr_data_p')]),
147
- EventClassInfo.new('finalize_usr_data',
148
- [GeneratedArg.new('void *', 'usr_data')]),
149
- EventClassInfo.new('read_params',
150
- [GeneratedArg.new('void *', 'usr_data'),
151
- GeneratedArg.new('btx_params_t *', 'usr_params')])]
152
-
153
- if options[:component_type] == 'SOURCE'
154
- component_dispatchers << EventClassInfo.new('push_usr_messages',
155
- [GeneratedArg.new('void *', 'usr_data'),
156
- GeneratedArg.new('btx_source_status_t*', 'status')])
157
- end
270
+ def validate_model(yaml)
271
+ # Stream and event classes must have a 'name' as minimum requirement.
272
+ raise "Missing 'name' attr in model #{yaml}" unless yaml[:stream_classes].all? do |d|
273
+ d.key?(:name) && d[:event_classes].all? do |d2|
274
+ d2.key?(:name)
275
+ end
276
+ end
158
277
 
159
- d2 = { component_dispatchers: component_dispatchers,
160
- event_name: 'dummy_event' }
278
+ # Event class name must be unique
279
+ events = yaml[:stream_classes].flat_map { |sc| sc[:event_classes] }.map { |e| e[:name] }
280
+ raise "Duplicated 'event' in model #{yaml}" unless events.length == events.uniq.length
161
281
 
162
- erb_render_and_save(d2.update(d).update(options: options), 'component.h', folder)
163
- erb_render_and_save(d2.update(d).update(options: options), 'component.c', folder)
282
+ yaml
164
283
  end
165
284
 
166
- # Display help if no arguments.
167
- ARGV << '-h' if ARGV.empty?
285
+ def load_models(models)
286
+ yaml = [models].flatten
287
+ .map { |f| YAML.load_file(f) }
288
+ .reduce({}) { |s, y| s.deep_merge(y) { |_key, old, new| old + new } }
289
+ validate_model(yaml)
290
+ end
168
291
 
169
- options = {}
170
- OptionParser.new do |opts|
171
- opts.banner = 'Usage: example.rb [options]'
292
+ class ContextBuilder
293
+ attr_accessor :cli_options
172
294
 
173
- opts.on('-h', '--help', 'Prints this help') do
174
- puts opts
175
- exit
295
+ def initialize
296
+ @cli_options = parse_argv
176
297
  end
177
298
 
178
- opts.on('-v', '--version', 'Prints this help') do
179
- puts "Ruby: #{RUBY_VERSION}"
180
- puts "Metababel: #{Metababel::VERSION}"
181
- exit
299
+ def base_folder
300
+ @base_folder ||= begin
301
+ f = @cli_options[:folder] || "#{@cli_options[:component_type]}.#{@cli_options[:plugin_name]}.#{@cli_options[:component_name]}"
302
+ FileUtils.mkdir_p(f)
303
+ f
304
+ end
182
305
  end
183
306
 
184
- opts.on('-t', '--component TYPE', '[Mandatory] Node within a trace processing graph.') do |p|
185
- options[:component_type] = p
307
+ def folder
308
+ @folder ||= begin
309
+ f = "#{base_folder}/metababel"
310
+ FileUtils.mkdir_p(f)
311
+ f
312
+ end
186
313
  end
187
314
 
188
- opts.on('-u', '--upstreams PATH', Array, '[Mandatory] Path to the bt2 yaml file.') do |p|
189
- options[:upstreams] = p
315
+ def options
316
+ { options: @cli_options }
190
317
  end
191
318
 
192
- opts.on('-d', '--downstream PATH', '[Optional] Path to the bt2 yaml file.') do |p|
193
- options[:downstream] = p
319
+ def params
320
+ @params ||= if @cli_options.key?(:params)
321
+ y = YAML.load_file(@cli_options[:params])
322
+ c = Babeltrace2Gen::BTValueCLass.from_h(y)
323
+ body = Babeltrace2Gen.context(indent: 1) do
324
+ c.get('_usr_params', '_params')
325
+ end
326
+ { params_declaration: c.get_struct_definition('_params'),
327
+ params_definition: body }
328
+ else
329
+ { params_declaration: nil, params_definition: nil }
330
+ end
194
331
  end
195
332
 
196
- opts.on('-p', '--plugin-name PATH', '[Optional] Name of the bt2 plugin created.') do |p|
197
- options[:plugin_name] = p
333
+ def trace_matcher
334
+ @trace_matcher ||= if @cli_options.key?(:matching)
335
+ data = YAML.load_file(@cli_options[:matching])
336
+ data[:match] = true
337
+ Babeltrace2Gen::BTTraceClass.from_h(nil, data)
338
+ else
339
+ Babeltrace2Gen::BTTraceClass.new(parent: nil, stream_classes: [])
340
+ end
198
341
  end
199
342
 
200
- opts.on('-c', '--component-name PATH', '[Optional] Name of the bt2 componant created.') do |p|
201
- options[:component_name] = p
202
- end
343
+ def callback_types
344
+ @callback_types ||= begin
345
+ callback_types = ['generic']
346
+ if @cli_options.key?(:matching)
347
+ event_classes = trace_matcher.stream_classes.map(&:event_classes).flatten(1).filter do |em|
348
+ raise "Key ':set_id' required for matching events." unless em.set_id
203
349
 
204
- opts.on('--params PATH', '[Optional] Name of YAML params definition.') do |p|
205
- options[:params] = p
206
- end
350
+ em.register
351
+ end
352
+ callback_types += event_classes.map { |em| "matching_#{sanitize(em.set_id)}" }
353
+ end
207
354
 
208
- opts.on('-o', '--output FOLDER', '[Optional] Output folder path.') do |p|
209
- options[:folder] = p
355
+ static_callbacks = [StaticDispatcher.new('initialize_component',
356
+ [GeneratedArg.new('void **', 'usr_data_p')],
357
+ no_btx_handle: true),
358
+ StaticDispatcher.new('finalize_component',
359
+ [GeneratedArg.new('void *', 'usr_data')],
360
+ no_btx_handle: true),
361
+ StaticDispatcher.new('read_params',
362
+ [GeneratedArg.new('void *', 'usr_data'),
363
+ GeneratedArg.new('btx_params_t *', 'usr_params')],
364
+ no_btx_handle: true)]
365
+ # Usefull to push message
366
+ if %w[SOURCE FILTER].include?(@cli_options[:component_type])
367
+ static_callbacks += [StaticDispatcher.new('initialize_processing',
368
+ [GeneratedArg.new('void *', 'usr_data_p')]),
369
+ StaticDispatcher.new('finalize_processing',
370
+ [GeneratedArg.new('void *', 'usr_data')])]
371
+ end
372
+
373
+ if %w[SOURCE].include?(@cli_options[:component_type])
374
+ static_callbacks << StaticDispatcher.new('push_usr_messages',
375
+ [GeneratedArg.new('void *', 'usr_data'),
376
+ GeneratedArg.new('btx_source_status_t*', 'status')])
377
+
378
+ end
379
+ { callback_types: callback_types,
380
+ static_callback_types: static_callbacks }
381
+ end
210
382
  end
211
383
 
212
- opts.on('-i', '--usr-data-header NAME', '[Optional] User datatypes definitions.') do |p|
213
- options[:usr_data_header] = p
384
+ def downstream
385
+ @downstream ||= begin
386
+ raise 'Missing downstream model' unless @cli_options[:downstream]
387
+
388
+ y = load_models(@cli_options[:downstream])
389
+ t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
390
+
391
+ event_name = '_event'
392
+ downstream_events = t.filter_map_event_classes_with_index do |e, index_stream_class, index_event_class, default_clock_class|
393
+ Dispatcher.new(e, event_name, 'setter', index_stream_class, index_event_class, default_clock_class)
394
+ end
395
+
396
+ body_declarator_classes = "\n" + Babeltrace2Gen.context(indent: 1) do
397
+ t.get_declarator(variable: '_trace_class', self_component: '_self_component')
398
+ end
399
+
400
+ { body_declarator_classes: body_declarator_classes,
401
+ downstream_events: downstream_events,
402
+ stream_classes: t.stream_classes,
403
+ event_name: event_name }
404
+ end
214
405
  end
215
- end.parse!
216
406
 
217
- raise OptionParser::MissingArgument if options[:component_type].nil?
407
+ def upstream
408
+ @upstream ||= begin
409
+ raise 'Missing upstreams models' unless @cli_options[:upstreams]
218
410
 
219
- options[:plugin_name] ||= "metababel_#{options[:component_type].downcase}"
220
- options[:component_name] ||= 'btx'
411
+ y = load_models(@cli_options[:upstreams])
412
+ t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
221
413
 
222
- # Babeltrace can be extended by plugins, which provide one or more component classes.
223
- base_folder = options[:folder] || "#{options[:component_type]}.#{options[:plugin_name]}.#{options[:component_name]}"
224
- folder = "#{base_folder}/metababel"
225
- FileUtils.mkdir_p(folder)
226
-
227
- d = { options: options }
228
-
229
- d[:params_declaration] = ''
230
- d[:params_definition] = ''
231
- if options.key?(:params)
232
- y = YAML.load_file(options[:params])
233
- c = Babeltrace2Gen::BTValueCLass.from_h(y)
234
- body = Babeltrace2Gen.context(indent: 1) do
235
- c.get('usr_params', 'params')
414
+ event_name = '_event'
415
+ dispatchers, automatic_dispatch_types = t.filter_map_event_classes_with_index do |e, index_stream_class, index_event_class, default_clock_class|
416
+ dispatcher = Dispatcher.new(e, event_name, 'getter', index_stream_class, index_event_class,
417
+ default_clock_class)
418
+ dispatch_type = DispatchType.new(e.name, dispatcher.args, 'generic', [dispatcher])
419
+ dispatcher.dispatch_types << dispatch_type
420
+
421
+ [dispatcher, dispatch_type]
422
+ end.transpose
423
+
424
+ context = { 'all' => dispatchers.to_set }
425
+ matching_dispatch_types = trace_matcher.filter_map_event_classes_with_index do |em, _, _, default_clock_class|
426
+ # We mutate context across iterations.
427
+ get_dispatch_type(em, default_clock_class, context)
428
+ end
429
+
430
+ { dispatchers: dispatchers,
431
+ dispatch_types: automatic_dispatch_types + matching_dispatch_types,
432
+ event_name: event_name }
433
+ end
434
+ end
435
+
436
+ def get_context(list_symbols)
437
+ d = {}
438
+ d.update(options) if list_symbols.include?('options')
439
+ d.update(params) if list_symbols.include?('params')
440
+ d.update(callback_types) if list_symbols.include?('callback_types')
441
+ d.update(static_callback_types) if list_symbols.include?('static_callback_types')
442
+ d.update(downstream) if list_symbols.include?('downstream')
443
+ d.update(upstream) if list_symbols.include?('upstream')
444
+ d
236
445
  end
237
- d[:params_declaration] = c.get_struct_definition('params')
238
- d[:params_definition] = body
239
- else
240
- d[:params_declaration] = 'char _dummy;'
241
446
  end
242
447
 
243
- erb_render_and_save(d, "#{options[:component_type].downcase}.c", base_folder, out_name: 'main.c')
244
- erb_render_and_save({ options: options }, 'metababel.h', folder, prefix: '')
448
+ def wrote_upstream(cb)
449
+ erb_render_and_save(cb.get_context(%w[upstream]), 'upstream.h', cb.folder)
450
+ erb_render_and_save(cb.get_context(%w[upstream]), 'upstream.c', cb.folder)
451
+ end
245
452
 
246
- wrote_component(options, d, folder)
247
- if %w[SOURCE FILTER].include?(options[:component_type])
248
- raise 'Missing downstream model' unless options[:downstream]
453
+ def wrote_downstream(cb)
454
+ erb_render_and_save(cb.get_context(%w[downstream options]), 'downstream.h', cb.folder)
455
+ erb_render_and_save(cb.get_context(%w[downstream options]), 'downstream.c', cb.folder)
456
+ end
249
457
 
250
- y = YAML.load_file(options[:downstream])
251
- validate_model(y)
252
- t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
253
- wrote_creates(folder, t)
458
+ def wrote_component(cb)
459
+ erb_render_and_save(cb.get_context(%w[options params callback_types]), 'component.h',
460
+ cb.folder)
461
+ erb_render_and_save(cb.get_context(%w[options params callback_types]), 'component.c',
462
+ cb.folder)
254
463
  end
255
464
 
256
- if %w[FILTER SINK].include?(options[:component_type])
257
- raise 'Missing upstream models' unless options[:upstreams]
465
+ def wrote_main(cb)
466
+ erb_render_and_save(cb.get_context(%w[params options]), "#{cb.cli_options[:component_type].downcase}.c",
467
+ cb.base_folder, out_name: 'main.c')
468
+ end
258
469
 
259
- y = options[:upstreams].reduce({}) do |y, upstream|
260
- # Need to specialize for merging arrays
261
- y.deep_merge(YAML.load_file(upstream)) { |_key, old, new| old + new }
262
- end
263
- validate_model(y)
264
- t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
265
- wrote_event_dispatchers(folder, t)
470
+ def wrote_header(cb)
471
+ erb_render_and_save(cb.get_context(%w[options]), 'metababel.h',
472
+ cb.folder, prefix: '')
266
473
  end
474
+
475
+ # Babeltrace can be extended by plugins, which provide one or more component classes.
476
+ context_builder = ContextBuilder.new
477
+ wrote_header(context_builder)
478
+ wrote_main(context_builder)
479
+ wrote_component(context_builder)
480
+ wrote_downstream(context_builder) if %w[SOURCE FILTER].include?(context_builder.cli_options[:component_type])
481
+ wrote_upstream(context_builder) if %w[FILTER SINK].include?(context_builder.cli_options[:component_type])