openc3 7.1.1 → 7.2.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.
- checksums.yaml +4 -4
- data/data/config/command_modifiers.yaml +2 -2
- data/data/config/item_modifiers.yaml +10 -3
- data/lib/openc3/api/tlm_api.rb +6 -0
- data/lib/openc3/microservices/microservice.rb +20 -5
- data/lib/openc3/operators/operator.rb +34 -9
- data/lib/openc3/packets/packet_config.rb +17 -4
- data/lib/openc3/script/suite.rb +1 -1
- data/lib/openc3/script/web_socket_api.rb +5 -1
- data/lib/openc3/utilities/cli_generator.rb +427 -403
- data/lib/openc3/utilities/questdb_client.rb +51 -4
- data/lib/openc3/utilities/running_script.rb +41 -3
- data/lib/openc3/utilities/simulated_target.rb +4 -2
- data/lib/openc3/version.rb +6 -6
- data/templates/command_validator/command_validator.py +8 -10
- data/templates/command_validator/command_validator.rb +6 -9
- data/templates/plugin/LICENSE.md +16 -4
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/widget/package.json +2 -2
- metadata +1 -1
|
@@ -16,40 +16,52 @@ module OpenC3
|
|
|
16
16
|
GENERATORS = %w(plugin target microservice widget conversion processor limits_response tool tool_vue tool_angular tool_react tool_svelte command_validator)
|
|
17
17
|
TEMPLATES_DIR = "#{File.dirname(__FILE__)}/../../../templates"
|
|
18
18
|
|
|
19
|
+
# Generators that derive language from the target's target.txt
|
|
20
|
+
TARGET_DERIVED_GENERATORS = %w(conversion processor limits_response command_validator).freeze
|
|
21
|
+
# Generators that are JavaScript-only and ignore language flags
|
|
22
|
+
JS_ONLY_GENERATORS = %w(widget tool tool_vue tool_angular tool_react tool_svelte).freeze
|
|
23
|
+
# Generators that require an explicit language (or env/plugin default)
|
|
24
|
+
LANGUAGE_REQUIRED_GENERATORS = %w(target microservice).freeze
|
|
25
|
+
|
|
19
26
|
# Called by openc3cli with ARGV[1..-1]
|
|
20
27
|
def self.generate(args)
|
|
21
28
|
if args[0].nil? || args[0] == '--help' || args[0] == '-h'
|
|
22
|
-
puts "Usage: cli generate GENERATOR [ARGS...]
|
|
29
|
+
puts "Usage: cli generate GENERATOR [ARGS...] [--ruby | --python]"
|
|
23
30
|
puts ""
|
|
24
31
|
puts "Generate COSMOS components from templates"
|
|
25
32
|
puts ""
|
|
26
33
|
puts "Available Generators:"
|
|
27
|
-
puts " plugin Create a new COSMOS plugin"
|
|
28
|
-
puts " target Create a new target within a plugin"
|
|
29
|
-
puts " microservice Create a new microservice within a plugin"
|
|
30
|
-
puts " widget Create a new custom widget"
|
|
31
|
-
puts " conversion Create a new conversion class for a target"
|
|
32
|
-
puts " processor Create a new processor for a target"
|
|
33
|
-
puts " limits_response Create a new limits response for a target"
|
|
34
|
-
puts " command_validator Create a new command validator for a target"
|
|
35
|
-
puts " tool Create a new tool
|
|
36
|
-
puts " tool_vue Create a new Vue.js tool"
|
|
37
|
-
puts " tool_angular Create a new Angular tool"
|
|
38
|
-
puts " tool_react Create a new React tool"
|
|
39
|
-
puts " tool_svelte Create a new Svelte tool"
|
|
34
|
+
puts " plugin Create a new COSMOS plugin (--ruby/--python optional, sets plugin default)"
|
|
35
|
+
puts " target Create a new target within a plugin (--ruby/--python required or inherited)"
|
|
36
|
+
puts " microservice Create a new microservice within a plugin (--ruby/--python required or inherited)"
|
|
37
|
+
puts " widget Create a new custom widget (JavaScript only)"
|
|
38
|
+
puts " conversion Create a new conversion class for a target (language inherited from target)"
|
|
39
|
+
puts " processor Create a new processor for a target (language inherited from target)"
|
|
40
|
+
puts " limits_response Create a new limits response for a target (language inherited from target)"
|
|
41
|
+
puts " command_validator Create a new command validator for a target (language inherited from target)"
|
|
42
|
+
puts " tool Create a new tool, Vue.js by default (JavaScript only)"
|
|
43
|
+
puts " tool_vue Create a new Vue.js tool (JavaScript only)"
|
|
44
|
+
puts " tool_angular Create a new Angular tool (JavaScript only)"
|
|
45
|
+
puts " tool_react Create a new React tool (JavaScript only)"
|
|
46
|
+
puts " tool_svelte Create a new Svelte tool (JavaScript only)"
|
|
40
47
|
puts ""
|
|
41
48
|
puts "Run 'cli generate GENERATOR --help' for detailed help on each generator."
|
|
42
49
|
puts ""
|
|
50
|
+
puts "Language Resolution (for target/microservice):"
|
|
51
|
+
puts " 1. --ruby or --python flag"
|
|
52
|
+
puts " 2. OPENC3_LANGUAGE environment variable"
|
|
53
|
+
puts " 3. '# LANGUAGE ruby|python' comment in plugin.txt (set by 'generate plugin --ruby/--python')"
|
|
54
|
+
puts ""
|
|
43
55
|
puts "Options:"
|
|
44
|
-
puts " --ruby Generate Ruby code
|
|
45
|
-
puts " --python Generate Python code
|
|
56
|
+
puts " --ruby Generate Ruby code"
|
|
57
|
+
puts " --python Generate Python code"
|
|
46
58
|
puts " -h, --help Show this help message"
|
|
47
59
|
puts ""
|
|
48
60
|
puts "Examples:"
|
|
49
|
-
puts " cli generate plugin MyPlugin --ruby"
|
|
50
|
-
puts " cli generate target EXAMPLE --python"
|
|
51
|
-
puts " cli generate widget SuperdataWidget
|
|
52
|
-
puts " cli generate conversion EXAMPLE STATUS
|
|
61
|
+
puts " cli generate plugin MyPlugin --ruby # Plugin defaults future generators to Ruby"
|
|
62
|
+
puts " cli generate target EXAMPLE --python # Or inherit from plugin's stored default"
|
|
63
|
+
puts " cli generate widget SuperdataWidget # No language flag needed"
|
|
64
|
+
puts " cli generate conversion EXAMPLE STATUS # Language read from targets/EXAMPLE/target.txt"
|
|
53
65
|
puts ""
|
|
54
66
|
puts "Documentation:"
|
|
55
67
|
puts " https://docs.openc3.com/docs/development/developing"
|
|
@@ -65,34 +77,259 @@ module OpenC3
|
|
|
65
77
|
send("generate_#{args[0].to_s.downcase.gsub('-', '_')}", args)
|
|
66
78
|
end
|
|
67
79
|
|
|
80
|
+
# Strip --ruby/--python tokens from args and return the resolved language ('rb'/'py'/nil).
|
|
81
|
+
# Aborts if both flags are supplied. Aborts if a language flag appears before the NAME
|
|
82
|
+
# positional arg (i.e. stripping flags would leave the generator with no NAME).
|
|
83
|
+
def self.extract_language!(args)
|
|
84
|
+
generator = args[0]
|
|
85
|
+
lang_flags = []
|
|
86
|
+
flag_indices = []
|
|
87
|
+
args.each_with_index do |arg, idx|
|
|
88
|
+
next if idx == 0 # don't touch the generator name itself
|
|
89
|
+
if arg == '--ruby' || arg == '--python'
|
|
90
|
+
lang_flags << arg
|
|
91
|
+
flag_indices << idx
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if lang_flags.size > 1 && lang_flags.uniq.size > 1
|
|
96
|
+
abort("Cannot specify both --ruby and --python.")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# If a language flag is present but no positional NAME follows the generator name,
|
|
100
|
+
# the user wrote something like `cli generate plugin --python`. Abort with guidance.
|
|
101
|
+
if args[1] == '--ruby' || args[1] == '--python'
|
|
102
|
+
abort("NAME must come before the language flag. Example: cli generate #{generator} MyName #{args[1]}")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Remove flag tokens from args in-place so downstream argument-position checks work.
|
|
106
|
+
flag_indices.reverse_each { |i| args.delete_at(i) }
|
|
107
|
+
|
|
108
|
+
case lang_flags.first
|
|
109
|
+
when '--python' then 'py'
|
|
110
|
+
when '--ruby' then 'rb'
|
|
111
|
+
else nil
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Read the '# LANGUAGE ruby|python' comment from plugin.txt in the current directory.
|
|
116
|
+
# Returns 'rb', 'py', or nil if the file or comment is absent.
|
|
117
|
+
def self.read_plugin_language
|
|
118
|
+
return nil unless File.exist?('plugin.txt')
|
|
119
|
+
File.foreach('plugin.txt') do |line|
|
|
120
|
+
if line =~ /^\s*#\s*LANGUAGE\s+(ruby|python)\b/i
|
|
121
|
+
return $1.downcase == 'python' ? 'py' : 'rb'
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Convert OPENC3_LANGUAGE env var to 'rb'/'py' or nil.
|
|
128
|
+
def self.env_language
|
|
129
|
+
case ENV['OPENC3_LANGUAGE']
|
|
130
|
+
when 'python' then 'py'
|
|
131
|
+
when 'ruby' then 'rb'
|
|
132
|
+
else nil
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Argument validation + language resolution dispatch.
|
|
137
|
+
# After this returns, args no longer contains --ruby/--python tokens and
|
|
138
|
+
# @@language is set (except for generators that resolve language later,
|
|
139
|
+
# like target-derived ones that read target.txt).
|
|
68
140
|
def self.check_args(args)
|
|
141
|
+
generator = args[0]
|
|
142
|
+
explicit_lang = extract_language!(args)
|
|
143
|
+
|
|
69
144
|
args.each do |arg|
|
|
70
|
-
if arg =~ /\s/ and
|
|
71
|
-
abort("#{
|
|
145
|
+
if arg =~ /\s/ and generator.to_s.downcase[0..3] != 'tool'
|
|
146
|
+
abort("#{generator.to_s.downcase} arguments can not have spaces!")
|
|
72
147
|
end
|
|
73
148
|
end
|
|
74
149
|
# All generators except 'plugin' must be within an existing plugin
|
|
75
|
-
if
|
|
76
|
-
abort("No gemspec file detected. #{
|
|
150
|
+
if generator != 'plugin' and Dir.glob("*.gemspec").empty?
|
|
151
|
+
abort("No gemspec file detected. #{generator.to_s.downcase} generator should be run within an existing plugin.")
|
|
77
152
|
end
|
|
78
153
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@@language = '
|
|
86
|
-
|
|
154
|
+
if JS_ONLY_GENERATORS.include?(generator)
|
|
155
|
+
if explicit_lang
|
|
156
|
+
puts "Note: --ruby/--python is ignored for the #{generator} generator (JavaScript only)."
|
|
157
|
+
end
|
|
158
|
+
# JS generators don't write any .rb/.py files but process_template still
|
|
159
|
+
# filters by @@language; set to 'rb' as a harmless default.
|
|
160
|
+
@@language = 'rb'
|
|
161
|
+
elsif TARGET_DERIVED_GENERATORS.include?(generator)
|
|
162
|
+
if explicit_lang
|
|
163
|
+
puts "Note: --ruby/--python is ignored for the #{generator} generator (language is inherited from the target's target.txt)."
|
|
164
|
+
end
|
|
165
|
+
# @@language is set later by the generator after it locates target.txt.
|
|
166
|
+
# Default to 'rb' here so any pre-target validation doesn't blow up.
|
|
87
167
|
@@language = 'rb'
|
|
88
|
-
|
|
89
|
-
|
|
168
|
+
elsif LANGUAGE_REQUIRED_GENERATORS.include?(generator)
|
|
169
|
+
gen_lang = explicit_lang || env_language || read_plugin_language
|
|
170
|
+
unless gen_lang
|
|
171
|
+
abort("Language required for #{generator} generator. Pass --ruby or --python, set OPENC3_LANGUAGE, or add '# LANGUAGE ruby|python' to plugin.txt (the plugin generator does this automatically when given --ruby/--python).")
|
|
172
|
+
end
|
|
173
|
+
@@language = gen_lang
|
|
174
|
+
else # plugin
|
|
175
|
+
@@language = explicit_lang || env_language
|
|
176
|
+
# nil is allowed for plugin; templates are language-agnostic at the plugin level.
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Shared prelude for generators that resolve language via the flag → env var
|
|
181
|
+
# → plugin.txt comment chain (target and microservice). Handles the --help
|
|
182
|
+
# branch and the "exactly one positional NAME arg" arity check. Returns
|
|
183
|
+
# normally only when args are valid and the caller should proceed.
|
|
184
|
+
def self.validate_language_inheriting_args!(generator, args, example:, docs:)
|
|
185
|
+
if args[1].nil? || args[1] == '--help' || args[1] == '-h'
|
|
186
|
+
print_help(
|
|
187
|
+
usage: "cli generate #{generator} NAME [--ruby | --python]",
|
|
188
|
+
description: "Generate a new #{generator} within an existing plugin",
|
|
189
|
+
arguments: [
|
|
190
|
+
"NAME Name of the #{generator} (required)",
|
|
191
|
+
' Will be uppercased and underscores/hyphens converted to underscores',
|
|
192
|
+
],
|
|
193
|
+
options: [
|
|
194
|
+
"--ruby Generate Ruby #{generator} (optional)",
|
|
195
|
+
"--python Generate Python #{generator} (optional)",
|
|
196
|
+
],
|
|
197
|
+
language_defaults: [
|
|
198
|
+
'1. OPENC3_LANGUAGE environment variable',
|
|
199
|
+
"2. '# LANGUAGE ruby|python' comment in plugin.txt",
|
|
200
|
+
],
|
|
201
|
+
example: example,
|
|
202
|
+
docs: docs,
|
|
203
|
+
exit_code: (args[1].nil? ? 1 : 0),
|
|
204
|
+
)
|
|
205
|
+
end
|
|
206
|
+
if args.length != 2
|
|
207
|
+
abort("Usage: cli generate #{generator} <NAME> [--ruby | --python]")
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Shared structure for every per-generator help block. Pass a hash with the
|
|
212
|
+
# generator's usage line, description, arg/option/example lines, etc.
|
|
213
|
+
# See generate_plugin / generate_target_artifact for examples.
|
|
214
|
+
def self.print_help(opts)
|
|
215
|
+
puts "Usage: #{opts[:usage]}"
|
|
216
|
+
puts ""
|
|
217
|
+
puts opts[:description]
|
|
218
|
+
puts ""
|
|
219
|
+
puts "Arguments:"
|
|
220
|
+
opts.fetch(:arguments, []).each { |line| puts " #{line}" }
|
|
221
|
+
puts ""
|
|
222
|
+
puts "Options:"
|
|
223
|
+
opts.fetch(:options, []).each { |line| puts " #{line}" }
|
|
224
|
+
puts " -h, --help Show this help message"
|
|
225
|
+
Array(opts[:notes]).each do |note|
|
|
226
|
+
puts ""
|
|
227
|
+
puts note
|
|
228
|
+
end
|
|
229
|
+
if opts[:language_defaults]
|
|
230
|
+
puts ""
|
|
231
|
+
puts "Language Defaults (used when --ruby/--python is not given):"
|
|
232
|
+
opts[:language_defaults].each { |line| puts " #{line}" }
|
|
233
|
+
end
|
|
234
|
+
if opts[:extra_section]
|
|
235
|
+
puts ""
|
|
236
|
+
puts "#{opts[:extra_section][:title]}:"
|
|
237
|
+
opts[:extra_section][:lines].each { |line| puts " #{line}" }
|
|
238
|
+
end
|
|
239
|
+
puts ""
|
|
240
|
+
puts "Example:"
|
|
241
|
+
Array(opts[:example]).each { |line| puts line.empty? ? "" : " #{line}" }
|
|
242
|
+
unless opts[:is_plugin]
|
|
243
|
+
puts ""
|
|
244
|
+
puts "Note: Must be run from within an existing plugin directory"
|
|
245
|
+
Array(opts[:in_plugin_extra]).each { |line| puts " #{line}" }
|
|
246
|
+
end
|
|
247
|
+
puts ""
|
|
248
|
+
puts "Documentation:"
|
|
249
|
+
puts " #{opts[:docs]}"
|
|
250
|
+
exit(opts[:exit_code])
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Single implementation backing the four target-derived generators.
|
|
254
|
+
def self.generate_target_artifact(args, config)
|
|
255
|
+
generator = args[0]
|
|
256
|
+
if args[1].nil? || args[2].nil? || args[1] == '--help' || args[1] == '-h'
|
|
257
|
+
print_help(
|
|
258
|
+
usage: "cli generate #{generator} TARGET NAME",
|
|
259
|
+
description: "Generate a new #{config[:kind].downcase} for an existing target",
|
|
260
|
+
arguments: [
|
|
261
|
+
'TARGET Target name (required, must exist)',
|
|
262
|
+
"NAME #{config[:kind]} name (required)",
|
|
263
|
+
" Will be uppercased with '_#{config[:suffix]}' suffix",
|
|
264
|
+
],
|
|
265
|
+
notes: [
|
|
266
|
+
"Note: Language is inherited from the target's target.txt (LANGUAGE keyword).",
|
|
267
|
+
' --ruby/--python flags are ignored.',
|
|
268
|
+
],
|
|
269
|
+
example: [
|
|
270
|
+
"cli generate #{generator} EXAMPLE #{config[:help_example]}",
|
|
271
|
+
"Creates: targets/EXAMPLE/lib/#{config[:help_example].downcase}_#{generator}.rb (or .py)",
|
|
272
|
+
],
|
|
273
|
+
docs: config[:docs],
|
|
274
|
+
exit_code: (args[1].nil? || args[2].nil? ? 1 : 0),
|
|
275
|
+
)
|
|
276
|
+
end
|
|
277
|
+
if args.length != 3
|
|
278
|
+
abort("Usage: cli generate #{generator} <TARGET> <NAME>")
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
target_name = args[1].upcase
|
|
282
|
+
target_path = "targets/#{target_name}"
|
|
283
|
+
unless File.exist?(target_path)
|
|
284
|
+
abort("Target '#{target_name}' does not exist! #{config[:kind_plural]} must be created for existing targets.")
|
|
285
|
+
end
|
|
286
|
+
@@language = read_target_language(target_path)
|
|
287
|
+
|
|
288
|
+
artifact_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_#{config[:suffix]}"
|
|
289
|
+
basename = "#{artifact_name.downcase}.#{@@language}"
|
|
290
|
+
filename = "#{target_path}/lib/#{basename}"
|
|
291
|
+
|
|
292
|
+
if File.exist?(filename)
|
|
293
|
+
abort("#{config[:kind]} #{filename} already exists!")
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Bind the class name to the template-specific local-variable name
|
|
297
|
+
# (e.g. conversion_class, processor_class) so the ERB templates resolve it.
|
|
298
|
+
template_binding = binding
|
|
299
|
+
template_binding.local_variable_set(config[:class_var].to_sym, basename.filename_to_class_name)
|
|
300
|
+
|
|
301
|
+
template_source = "#{config[:template_source]}.#{@@language}"
|
|
302
|
+
process_template("#{TEMPLATES_DIR}/#{config[:template]}", template_binding) do |fname|
|
|
303
|
+
fname.sub!(template_source, filename)
|
|
304
|
+
false
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
puts "#{config[:kind]} #{filename} successfully generated!"
|
|
308
|
+
puts config[:usage_intro]
|
|
309
|
+
directive = config[:usage_directive] % { basename: basename, name_upcase: args[2].upcase }
|
|
310
|
+
puts " #{directive}"
|
|
311
|
+
artifact_name
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Read 'LANGUAGE ruby|python' from a target's target.txt. Aborts if missing.
|
|
315
|
+
def self.read_target_language(target_path)
|
|
316
|
+
target_txt = "#{target_path}/target.txt"
|
|
317
|
+
unless File.exist?(target_txt)
|
|
318
|
+
abort("Could not find #{target_txt} to determine target language.")
|
|
90
319
|
end
|
|
320
|
+
File.foreach(target_txt) do |line|
|
|
321
|
+
if line =~ /^\s*LANGUAGE\s+(ruby|python)\b/i
|
|
322
|
+
return $1.downcase == 'python' ? 'py' : 'rb'
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
abort("No LANGUAGE keyword found in #{target_txt}. Add 'LANGUAGE ruby' or 'LANGUAGE python' to determine the language for generated files.")
|
|
91
326
|
end
|
|
92
327
|
|
|
93
328
|
def self.process_template(template_dir, the_binding)
|
|
94
329
|
Dir.glob("#{template_dir}/**/*", File::FNM_DOTMATCH).each do |file|
|
|
95
330
|
next if File.basename(file) == '.'
|
|
331
|
+
# When @@language is nil (plugin generation with no language specified),
|
|
332
|
+
# don't filter — let all template files through.
|
|
96
333
|
if @@language == 'rb' and File.extname(file) == '.py'
|
|
97
334
|
# Ignore python files if we're ruby
|
|
98
335
|
next
|
|
@@ -115,30 +352,35 @@ module OpenC3
|
|
|
115
352
|
|
|
116
353
|
def self.generate_plugin(args)
|
|
117
354
|
if args[1].nil? || args[1] == '--help' || args[1] == '-h'
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
355
|
+
print_help(
|
|
356
|
+
usage: 'cli generate plugin NAME [--ruby | --python]',
|
|
357
|
+
description: 'Generate a new COSMOS plugin',
|
|
358
|
+
arguments: [
|
|
359
|
+
'NAME Name of the plugin (required)',
|
|
360
|
+
" Will be prefixed with 'openc3-cosmos-'",
|
|
361
|
+
' Spaces, underscores, and hyphens will be converted to hyphens',
|
|
362
|
+
],
|
|
363
|
+
options: [
|
|
364
|
+
"--ruby Set the plugin's default language to Ruby. Subsequent",
|
|
365
|
+
" 'cli generate target/microservice' invocations inside this",
|
|
366
|
+
' plugin will default to Ruby. Recorded as a',
|
|
367
|
+
" '# LANGUAGE ruby' comment in plugin.txt.",
|
|
368
|
+
'--python Same as --ruby, but sets the default to Python.',
|
|
369
|
+
],
|
|
370
|
+
example: [
|
|
371
|
+
'cli generate plugin demo --ruby',
|
|
372
|
+
"Creates: openc3-cosmos-demo/ with '# LANGUAGE ruby' in plugin.txt",
|
|
373
|
+
'',
|
|
374
|
+
'cli generate plugin demo',
|
|
375
|
+
'Creates: openc3-cosmos-demo/ with no language default',
|
|
376
|
+
],
|
|
377
|
+
is_plugin: true,
|
|
378
|
+
docs: 'https://docs.openc3.com/docs/configuration/plugins',
|
|
379
|
+
exit_code: (args[1].nil? ? 1 : 0),
|
|
380
|
+
)
|
|
381
|
+
end
|
|
382
|
+
if args.length != 2
|
|
383
|
+
abort("Usage: cli generate #{args[0]} <NAME> [--ruby | --python]")
|
|
142
384
|
end
|
|
143
385
|
|
|
144
386
|
# Create the local variables that are used in process_template below (see openc3/templates/plugin/plugin.gemspec as an example)
|
|
@@ -156,38 +398,25 @@ module OpenC3
|
|
|
156
398
|
false
|
|
157
399
|
end
|
|
158
400
|
|
|
401
|
+
# If a language was specified, persist it in plugin.txt so future target /
|
|
402
|
+
# microservice generators can default to it.
|
|
403
|
+
if @@language
|
|
404
|
+
lang_word = (@@language == 'py') ? 'python' : 'ruby'
|
|
405
|
+
existing = File.exist?('plugin.txt') ? File.read('plugin.txt') : ''
|
|
406
|
+
File.open('plugin.txt', 'w') do |file|
|
|
407
|
+
file.puts "# LANGUAGE #{lang_word}"
|
|
408
|
+
file.write(existing)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
159
412
|
puts "Plugin #{plugin_name} successfully generated!"
|
|
160
413
|
return plugin_name
|
|
161
414
|
end
|
|
162
415
|
|
|
163
416
|
def self.generate_target(args)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
puts "Generate a new target within an existing plugin"
|
|
168
|
-
puts ""
|
|
169
|
-
puts "Arguments:"
|
|
170
|
-
puts " NAME Name of the target (required)"
|
|
171
|
-
puts " Will be uppercased and underscores/hyphens converted to underscores"
|
|
172
|
-
puts ""
|
|
173
|
-
puts "Options:"
|
|
174
|
-
puts " --ruby Generate Ruby target (or set OPENC3_LANGUAGE=ruby)"
|
|
175
|
-
puts " --python Generate Python target (or set OPENC3_LANGUAGE=python)"
|
|
176
|
-
puts " -h, --help Show this help message"
|
|
177
|
-
puts ""
|
|
178
|
-
puts "Example:"
|
|
179
|
-
puts " cli generate target EXAMPLE --ruby"
|
|
180
|
-
puts " Creates: targets/EXAMPLE/"
|
|
181
|
-
puts ""
|
|
182
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
183
|
-
puts ""
|
|
184
|
-
puts "Documentation:"
|
|
185
|
-
puts " https://docs.openc3.com/docs/configuration/target"
|
|
186
|
-
exit(args[1].nil? ? 1 : 0)
|
|
187
|
-
end
|
|
188
|
-
if args.length < 2 or args.length > 3
|
|
189
|
-
abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
|
|
190
|
-
end
|
|
417
|
+
validate_language_inheriting_args!('target', args,
|
|
418
|
+
example: ['cli generate target EXAMPLE --ruby', 'Creates: targets/EXAMPLE/'],
|
|
419
|
+
docs: 'https://docs.openc3.com/docs/configuration/target')
|
|
191
420
|
|
|
192
421
|
# Create the local variables
|
|
193
422
|
target_name = args[1].upcase.gsub(/_+|-+/, '_')
|
|
@@ -259,33 +488,9 @@ RUBY
|
|
|
259
488
|
end
|
|
260
489
|
|
|
261
490
|
def self.generate_microservice(args)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
puts "Generate a new microservice within an existing plugin"
|
|
266
|
-
puts ""
|
|
267
|
-
puts "Arguments:"
|
|
268
|
-
puts " NAME Name of the microservice (required)"
|
|
269
|
-
puts " Will be uppercased and underscores/hyphens converted to underscores"
|
|
270
|
-
puts ""
|
|
271
|
-
puts "Options:"
|
|
272
|
-
puts " --ruby Generate Ruby microservice (or set OPENC3_LANGUAGE=ruby)"
|
|
273
|
-
puts " --python Generate Python microservice (or set OPENC3_LANGUAGE=python)"
|
|
274
|
-
puts " -h, --help Show this help message"
|
|
275
|
-
puts ""
|
|
276
|
-
puts "Example:"
|
|
277
|
-
puts " cli generate microservice DATA_PROCESSOR --ruby"
|
|
278
|
-
puts " Creates: microservices/DATA_PROCESSOR/"
|
|
279
|
-
puts ""
|
|
280
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
281
|
-
puts ""
|
|
282
|
-
puts "Documentation:"
|
|
283
|
-
puts " https://docs.openc3.com/docs/configuration/plugins#microservices"
|
|
284
|
-
exit(args[1].nil? ? 1 : 0)
|
|
285
|
-
end
|
|
286
|
-
if args.length < 2 or args.length > 3
|
|
287
|
-
abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
|
|
288
|
-
end
|
|
491
|
+
validate_language_inheriting_args!('microservice', args,
|
|
492
|
+
example: ['cli generate microservice DATA_PROCESSOR --ruby', 'Creates: microservices/DATA_PROCESSOR/'],
|
|
493
|
+
docs: 'https://docs.openc3.com/docs/configuration/plugins#microservices')
|
|
289
494
|
|
|
290
495
|
# Create the local variables
|
|
291
496
|
microservice_name = args[1].upcase.gsub(/_+|-+/, '_')
|
|
@@ -331,32 +536,25 @@ RUBY
|
|
|
331
536
|
|
|
332
537
|
def self.generate_widget(args)
|
|
333
538
|
if args[1].nil? || args[1] == '--help' || args[1] == '-h'
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
puts ""
|
|
354
|
-
puts "Documentation:"
|
|
355
|
-
puts " https://docs.openc3.com/docs/guides/custom-widgets"
|
|
356
|
-
exit(args[1].nil? ? 1 : 0)
|
|
357
|
-
end
|
|
358
|
-
if args.length < 2 or args.length > 3
|
|
359
|
-
abort("Usage: cli generate #{args[0]} <SuperdataWidget> (--ruby or --python)")
|
|
539
|
+
print_help(
|
|
540
|
+
usage: 'cli generate widget NAME',
|
|
541
|
+
description: 'Generate a new custom Vue.js widget within an existing plugin',
|
|
542
|
+
arguments: [
|
|
543
|
+
'NAME Name of the widget (required)',
|
|
544
|
+
" Must be CapitalCase ending with 'Widget'",
|
|
545
|
+
' Example: SuperdataWidget, StatusWidget',
|
|
546
|
+
],
|
|
547
|
+
notes: 'Note: Widgets are JavaScript only. --ruby/--python flags are ignored.',
|
|
548
|
+
example: [
|
|
549
|
+
'cli generate widget SuperdataWidget',
|
|
550
|
+
'Creates: src/SuperdataWidget.vue',
|
|
551
|
+
],
|
|
552
|
+
docs: 'https://docs.openc3.com/docs/guides/custom-widgets',
|
|
553
|
+
exit_code: (args[1].nil? ? 1 : 0),
|
|
554
|
+
)
|
|
555
|
+
end
|
|
556
|
+
if args.length != 2
|
|
557
|
+
abort("Usage: cli generate #{args[0]} <SuperdataWidget>")
|
|
360
558
|
end
|
|
361
559
|
# Per https://stackoverflow.com/a/47591707/453280
|
|
362
560
|
if args[1] !~ /.*Widget$/ or args[1][0...-6] != args[1][0...-6].capitalize
|
|
@@ -403,8 +601,13 @@ RUBY
|
|
|
403
601
|
def self.generate_tool(args)
|
|
404
602
|
if args[1].nil? || args[1] == '--help' || args[1] == '-h'
|
|
405
603
|
tool_type = args[0].to_s.downcase.gsub('-', '_')
|
|
604
|
+
common_args = [
|
|
605
|
+
'TOOL NAME Display name of the tool (required, can include spaces)',
|
|
606
|
+
' Will be converted to lowercase without spaces for directory name',
|
|
607
|
+
]
|
|
608
|
+
common_note = 'Note: Tools are JavaScript only. --ruby/--python flags are ignored.'
|
|
609
|
+
docs_url = 'https://docs.openc3.com/docs/guides/custom-tools'
|
|
406
610
|
|
|
407
|
-
# Specific help for tool variants
|
|
408
611
|
if tool_type != 'tool'
|
|
409
612
|
framework = case tool_type
|
|
410
613
|
when 'tool_vue' then 'Vue.js'
|
|
@@ -413,65 +616,46 @@ RUBY
|
|
|
413
616
|
when 'tool_svelte' then 'Svelte'
|
|
414
617
|
else 'Custom'
|
|
415
618
|
end
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
puts ""
|
|
430
|
-
puts "Example:"
|
|
431
|
-
puts " cli generate #{args[0]} 'Data Viewer' --ruby"
|
|
432
|
-
puts " Creates: tools/dataviewer/ (#{framework}-based)"
|
|
433
|
-
puts ""
|
|
434
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
435
|
-
puts " For other tool types, see: cli generate tool --help"
|
|
436
|
-
puts ""
|
|
437
|
-
puts "Documentation:"
|
|
438
|
-
puts " https://docs.openc3.com/docs/guides/custom-tools"
|
|
439
|
-
exit(args[1].nil? ? 1 : 0)
|
|
619
|
+
print_help(
|
|
620
|
+
usage: "cli generate #{args[0]} 'TOOL NAME'",
|
|
621
|
+
description: "Generate a new #{framework} tool within an existing plugin",
|
|
622
|
+
arguments: common_args,
|
|
623
|
+
notes: common_note,
|
|
624
|
+
example: [
|
|
625
|
+
"cli generate #{args[0]} 'Data Viewer'",
|
|
626
|
+
"Creates: tools/dataviewer/ (#{framework}-based)",
|
|
627
|
+
],
|
|
628
|
+
in_plugin_extra: 'For other tool types, see: cli generate tool --help',
|
|
629
|
+
docs: docs_url,
|
|
630
|
+
exit_code: (args[1].nil? ? 1 : 0),
|
|
631
|
+
)
|
|
440
632
|
else
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
puts " cli generate tool 'Data Viewer' --ruby"
|
|
464
|
-
puts " Creates: tools/dataviewer/"
|
|
465
|
-
puts ""
|
|
466
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
467
|
-
puts ""
|
|
468
|
-
puts "Documentation:"
|
|
469
|
-
puts " https://docs.openc3.com/docs/guides/custom-tools"
|
|
470
|
-
exit(args[1].nil? ? 1 : 0)
|
|
633
|
+
print_help(
|
|
634
|
+
usage: "cli generate #{args[0]} 'TOOL NAME'",
|
|
635
|
+
description: 'Generate a new custom tool within an existing plugin',
|
|
636
|
+
arguments: common_args,
|
|
637
|
+
notes: common_note,
|
|
638
|
+
extra_section: {
|
|
639
|
+
title: 'Tool Types',
|
|
640
|
+
lines: [
|
|
641
|
+
'tool Generate Vue.js tool (default)',
|
|
642
|
+
'tool_vue Generate Vue.js tool',
|
|
643
|
+
'tool_angular Generate Angular tool',
|
|
644
|
+
'tool_react Generate React tool',
|
|
645
|
+
'tool_svelte Generate Svelte tool',
|
|
646
|
+
],
|
|
647
|
+
},
|
|
648
|
+
example: [
|
|
649
|
+
"cli generate tool 'Data Viewer'",
|
|
650
|
+
'Creates: tools/dataviewer/',
|
|
651
|
+
],
|
|
652
|
+
docs: docs_url,
|
|
653
|
+
exit_code: (args[1].nil? ? 1 : 0),
|
|
654
|
+
)
|
|
471
655
|
end
|
|
472
656
|
end
|
|
473
|
-
if args.length
|
|
474
|
-
abort("Usage: cli generate #{args[0]} 'Tool Name'
|
|
657
|
+
if args.length != 2
|
|
658
|
+
abort("Usage: cli generate #{args[0]} 'Tool Name'")
|
|
475
659
|
end
|
|
476
660
|
|
|
477
661
|
# Create the local variables
|
|
@@ -521,223 +705,63 @@ RUBY
|
|
|
521
705
|
self.singleton_class.send(:alias_method, :generate_tool_svelte, :generate_tool)
|
|
522
706
|
|
|
523
707
|
def self.generate_conversion(args)
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
puts " --python Generate Python conversion (or set OPENC3_LANGUAGE=python)"
|
|
537
|
-
puts " -h, --help Show this help message"
|
|
538
|
-
puts ""
|
|
539
|
-
puts "Example:"
|
|
540
|
-
puts " cli generate conversion EXAMPLE STATUS --ruby"
|
|
541
|
-
puts " Creates: targets/EXAMPLE/lib/status_conversion.rb"
|
|
542
|
-
puts ""
|
|
543
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
544
|
-
puts ""
|
|
545
|
-
puts "Documentation:"
|
|
546
|
-
puts " https://docs.openc3.com/docs/configuration/telemetry#read_conversion"
|
|
547
|
-
exit(args[1].nil? || args[2].nil? ? 1 : 0)
|
|
548
|
-
end
|
|
549
|
-
if args.length < 3 or args.length > 4
|
|
550
|
-
abort("Usage: cli generate conversion <TARGET> <NAME> (--ruby or --python)")
|
|
551
|
-
end
|
|
552
|
-
|
|
553
|
-
# Create the local variables
|
|
554
|
-
target_name = args[1].upcase
|
|
555
|
-
unless File.exist?("targets/#{target_name}")
|
|
556
|
-
abort("Target '#{target_name}' does not exist! Conversions must be created for existing targets.")
|
|
557
|
-
end
|
|
558
|
-
conversion_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_CONVERSION"
|
|
559
|
-
conversion_basename = "#{conversion_name.downcase}.#{@@language}"
|
|
560
|
-
conversion_class = conversion_basename.filename_to_class_name
|
|
561
|
-
conversion_class.inspect # Remove unused variable warning. These are used in binding for generator
|
|
562
|
-
conversion_filename = "targets/#{target_name}/lib/#{conversion_basename}"
|
|
563
|
-
if File.exist?(conversion_filename)
|
|
564
|
-
abort("Conversion #{conversion_filename} already exists!")
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
process_template("#{TEMPLATES_DIR}/conversion", binding) do |filename|
|
|
568
|
-
filename.sub!("conversion.#{@@language}", conversion_filename)
|
|
569
|
-
false
|
|
570
|
-
end
|
|
571
|
-
|
|
572
|
-
puts "Conversion #{conversion_filename} successfully generated!"
|
|
573
|
-
puts "To use the conversion add the following to a telemetry item:"
|
|
574
|
-
puts " READ_CONVERSION #{conversion_basename}"
|
|
575
|
-
return conversion_name
|
|
708
|
+
generate_target_artifact(args, {
|
|
709
|
+
suffix: 'CONVERSION',
|
|
710
|
+
kind: 'Conversion',
|
|
711
|
+
kind_plural: 'Conversions',
|
|
712
|
+
template: 'conversion',
|
|
713
|
+
template_source: 'conversion', # template file is conversion.rb / conversion.py
|
|
714
|
+
class_var: 'conversion_class',
|
|
715
|
+
usage_intro: 'To use the conversion add the following to a telemetry item:',
|
|
716
|
+
usage_directive: 'READ_CONVERSION %{basename}',
|
|
717
|
+
docs: 'https://docs.openc3.com/docs/configuration/telemetry#read_conversion',
|
|
718
|
+
help_example: 'STATUS',
|
|
719
|
+
})
|
|
576
720
|
end
|
|
577
721
|
|
|
578
722
|
def self.generate_processor(args)
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
puts " --python Generate Python processor (or set OPENC3_LANGUAGE=python)"
|
|
592
|
-
puts " -h, --help Show this help message"
|
|
593
|
-
puts ""
|
|
594
|
-
puts "Example:"
|
|
595
|
-
puts " cli generate processor EXAMPLE DATA --ruby"
|
|
596
|
-
puts " Creates: targets/EXAMPLE/lib/data_processor.rb"
|
|
597
|
-
puts ""
|
|
598
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
599
|
-
puts ""
|
|
600
|
-
puts "Documentation:"
|
|
601
|
-
puts " https://docs.openc3.com/docs/configuration/telemetry#processor"
|
|
602
|
-
exit(args[1].nil? || args[2].nil? ? 1 : 0)
|
|
603
|
-
end
|
|
604
|
-
if args.length < 3 or args.length > 4
|
|
605
|
-
abort("Usage: cli generate processor <TARGET> <NAME> (--ruby or --python)")
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
# Create the local variables
|
|
609
|
-
target_name = args[1].upcase
|
|
610
|
-
unless File.exist?("targets/#{target_name}")
|
|
611
|
-
abort("Target '#{target_name}' does not exist! Processors must be created for existing targets.")
|
|
612
|
-
end
|
|
613
|
-
processor_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_PROCESSOR"
|
|
614
|
-
processor_basename = "#{processor_name.downcase}.#{@@language}"
|
|
615
|
-
processor_class = processor_basename.filename_to_class_name
|
|
616
|
-
processor_class.inspect # Remove unused variable warning. These are used in binding for generator
|
|
617
|
-
processor_filename = "targets/#{target_name}/lib/#{processor_basename}"
|
|
618
|
-
if File.exist?(processor_filename)
|
|
619
|
-
abort("Processor #{processor_filename} already exists!")
|
|
620
|
-
end
|
|
621
|
-
|
|
622
|
-
process_template("#{TEMPLATES_DIR}/processor", binding) do |filename|
|
|
623
|
-
filename.sub!("processor.#{@@language}", processor_filename)
|
|
624
|
-
false
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
puts "Processor #{processor_filename} successfully generated!"
|
|
628
|
-
puts "To use the processor add the following to a telemetry packet:"
|
|
629
|
-
puts " PROCESSOR #{args[2].upcase} #{processor_basename} <PARAMS...>"
|
|
630
|
-
return processor_name
|
|
723
|
+
generate_target_artifact(args, {
|
|
724
|
+
suffix: 'PROCESSOR',
|
|
725
|
+
kind: 'Processor',
|
|
726
|
+
kind_plural: 'Processors',
|
|
727
|
+
template: 'processor',
|
|
728
|
+
template_source: 'processor',
|
|
729
|
+
class_var: 'processor_class',
|
|
730
|
+
usage_intro: 'To use the processor add the following to a telemetry packet:',
|
|
731
|
+
usage_directive: 'PROCESSOR %{name_upcase} %{basename} <PARAMS...>',
|
|
732
|
+
docs: 'https://docs.openc3.com/docs/configuration/telemetry#processor',
|
|
733
|
+
help_example: 'DATA',
|
|
734
|
+
})
|
|
631
735
|
end
|
|
632
736
|
|
|
633
737
|
def self.generate_limits_response(args)
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
puts " --python Generate Python limits response (or set OPENC3_LANGUAGE=python)"
|
|
647
|
-
puts " -h, --help Show this help message"
|
|
648
|
-
puts ""
|
|
649
|
-
puts "Example:"
|
|
650
|
-
puts " cli generate limits_response EXAMPLE CUSTOM --ruby"
|
|
651
|
-
puts " Creates: targets/EXAMPLE/lib/custom_limits_response.rb"
|
|
652
|
-
puts ""
|
|
653
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
654
|
-
puts ""
|
|
655
|
-
puts "Documentation:"
|
|
656
|
-
puts " https://docs.openc3.com/docs/configuration/telemetry#limits_response"
|
|
657
|
-
exit(args[1].nil? || args[2].nil? ? 1 : 0)
|
|
658
|
-
end
|
|
659
|
-
if args.length < 3 or args.length > 4
|
|
660
|
-
abort("Usage: cli generate limits_response <TARGET> <NAME> (--ruby or --python)")
|
|
661
|
-
end
|
|
662
|
-
|
|
663
|
-
# Create the local variables
|
|
664
|
-
target_name = args[1].upcase
|
|
665
|
-
unless File.exist?("targets/#{target_name}")
|
|
666
|
-
abort("Target '#{target_name}' does not exist! Limits responses must be created for existing targets.")
|
|
667
|
-
end
|
|
668
|
-
response_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_LIMITS_RESPONSE"
|
|
669
|
-
response_basename = "#{response_name.downcase}.#{@@language}"
|
|
670
|
-
response_filename = "targets/#{target_name}/lib/#{response_basename}"
|
|
671
|
-
response_class = response_basename.filename_to_class_name
|
|
672
|
-
response_class.inspect # Remove unused variable warning. These are used in binding for generator
|
|
673
|
-
if File.exist?(response_filename)
|
|
674
|
-
abort("response #{response_filename} already exists!")
|
|
675
|
-
end
|
|
676
|
-
|
|
677
|
-
process_template("#{TEMPLATES_DIR}/limits_response", binding) do |filename|
|
|
678
|
-
filename.sub!("response.#{@@language}", response_filename)
|
|
679
|
-
false
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
puts "Limits response #{response_filename} successfully generated!"
|
|
683
|
-
puts "To use the limits response add the following to a telemetry item:"
|
|
684
|
-
puts " LIMITS_RESPONSE #{response_basename}"
|
|
685
|
-
return response_name
|
|
738
|
+
generate_target_artifact(args, {
|
|
739
|
+
suffix: 'LIMITS_RESPONSE',
|
|
740
|
+
kind: 'Limits response',
|
|
741
|
+
kind_plural: 'Limits responses',
|
|
742
|
+
template: 'limits_response',
|
|
743
|
+
template_source: 'response', # template file is response.rb / response.py
|
|
744
|
+
class_var: 'response_class',
|
|
745
|
+
usage_intro: 'To use the limits response add the following to a telemetry item:',
|
|
746
|
+
usage_directive: 'LIMITS_RESPONSE %{basename}',
|
|
747
|
+
docs: 'https://docs.openc3.com/docs/configuration/telemetry#limits_response',
|
|
748
|
+
help_example: 'CUSTOM',
|
|
749
|
+
})
|
|
686
750
|
end
|
|
687
751
|
|
|
688
752
|
def self.generate_command_validator(args)
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
puts " --python Generate Python command validator (or set OPENC3_LANGUAGE=python)"
|
|
702
|
-
puts " -h, --help Show this help message"
|
|
703
|
-
puts ""
|
|
704
|
-
puts "Example:"
|
|
705
|
-
puts " cli generate command_validator EXAMPLE RANGE --ruby"
|
|
706
|
-
puts " Creates: targets/EXAMPLE/lib/range_command_validator.rb"
|
|
707
|
-
puts ""
|
|
708
|
-
puts "Note: Must be run from within an existing plugin directory"
|
|
709
|
-
puts ""
|
|
710
|
-
puts "Documentation:"
|
|
711
|
-
puts " https://docs.openc3.com/docs/configuration/command#validator"
|
|
712
|
-
exit(args[1].nil? || args[2].nil? ? 1 : 0)
|
|
713
|
-
end
|
|
714
|
-
if args.length < 3 or args.length > 4
|
|
715
|
-
abort("Usage: cli generate command_validator <TARGET> <NAME> (--ruby or --python)")
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
# Create the local variables
|
|
719
|
-
target_name = args[1].upcase
|
|
720
|
-
unless File.exist?("targets/#{target_name}")
|
|
721
|
-
abort("Target '#{target_name}' does not exist! Command validators must be created for existing targets.")
|
|
722
|
-
end
|
|
723
|
-
validator_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_COMMAND_VALIDATOR"
|
|
724
|
-
validator_basename = "#{validator_name.downcase}.#{@@language}"
|
|
725
|
-
validator_class = validator_basename.filename_to_class_name
|
|
726
|
-
validator_class.inspect # Remove unused variable warning. These are used in binding for generator
|
|
727
|
-
validator_filename = "targets/#{target_name}/lib/#{validator_basename}"
|
|
728
|
-
if File.exist?(validator_filename)
|
|
729
|
-
abort("Command validator #{validator_filename} already exists!")
|
|
730
|
-
end
|
|
731
|
-
|
|
732
|
-
process_template("#{TEMPLATES_DIR}/command_validator", binding) do |filename|
|
|
733
|
-
filename.sub!("command_validator.#{@@language}", validator_filename)
|
|
734
|
-
false
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
puts "Command validator #{validator_filename} successfully generated!"
|
|
738
|
-
puts "To use the command validator add the following to a command:"
|
|
739
|
-
puts " VALIDATOR #{validator_basename}"
|
|
740
|
-
return validator_name
|
|
753
|
+
generate_target_artifact(args, {
|
|
754
|
+
suffix: 'COMMAND_VALIDATOR',
|
|
755
|
+
kind: 'Command validator',
|
|
756
|
+
kind_plural: 'Command validators',
|
|
757
|
+
template: 'command_validator',
|
|
758
|
+
template_source: 'command_validator',
|
|
759
|
+
class_var: 'validator_class',
|
|
760
|
+
usage_intro: 'To use the command validator add the following to a command:',
|
|
761
|
+
usage_directive: 'VALIDATOR %{basename}',
|
|
762
|
+
docs: 'https://docs.openc3.com/docs/configuration/command#validator',
|
|
763
|
+
help_example: 'RANGE',
|
|
764
|
+
})
|
|
741
765
|
end
|
|
742
766
|
end
|
|
743
767
|
end
|