metababel 0.1.0 → 1.0.2

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