cosmos 5.0.4 → 5.0.5
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/bin/cosmos +182 -41
- data/data/config/plugins.yaml +10 -0
- data/ext/cosmos/ext/cosmos_io/cosmos_io.c +14 -14
- data/ext/cosmos/ext/packet/packet.c +3 -3
- data/ext/cosmos/ext/structure/structure.c +31 -31
- data/lib/cosmos/api/tlm_api.rb +4 -4
- data/lib/cosmos/logs/log_writer.rb +76 -27
- data/lib/cosmos/microservices/interface_microservice.rb +0 -15
- data/lib/cosmos/models/gem_model.rb +7 -1
- data/lib/cosmos/models/interface_model.rb +16 -7
- data/lib/cosmos/models/metadata_model.rb +39 -15
- data/lib/cosmos/models/microservice_model.rb +6 -3
- data/lib/cosmos/models/model.rb +7 -0
- data/lib/cosmos/models/note_model.rb +4 -6
- data/lib/cosmos/models/plugin_model.rb +107 -47
- data/lib/cosmos/models/scope_model.rb +2 -0
- data/lib/cosmos/models/sorted_model.rb +3 -1
- data/lib/cosmos/models/target_model.rb +24 -15
- data/lib/cosmos/models/tool_model.rb +8 -8
- data/lib/cosmos/models/widget_model.rb +10 -10
- data/lib/cosmos/packets/packet.rb +1 -1
- data/lib/cosmos/packets/structure.rb +30 -33
- data/lib/cosmos/script/calendar.rb +13 -2
- data/lib/cosmos/tools/table_manager/table_config.rb +16 -1
- data/lib/cosmos/tools/table_manager/table_manager_core.rb +213 -309
- data/lib/cosmos/topics/config_topic.rb +68 -0
- data/lib/cosmos/version.rb +5 -5
- metadata +7 -8
- data/bin/xtce_converter +0 -92
@@ -32,6 +32,7 @@ require 'cosmos/models/tool_model'
|
|
32
32
|
require 'cosmos/models/widget_model'
|
33
33
|
require 'cosmos/models/microservice_model'
|
34
34
|
require 'tmpdir'
|
35
|
+
require 'tempfile'
|
35
36
|
|
36
37
|
module Cosmos
|
37
38
|
# Represents a COSMOS plugin that can consist of targets, interfaces, routers
|
@@ -41,6 +42,9 @@ module Cosmos
|
|
41
42
|
PRIMARY_KEY = 'cosmos_plugins'
|
42
43
|
|
43
44
|
attr_accessor :variables
|
45
|
+
attr_accessor :plugin_txt_lines
|
46
|
+
attr_accessor :needs_dependencies
|
47
|
+
|
44
48
|
|
45
49
|
# NOTE: The following three class methods are used by the ModelController
|
46
50
|
# and are reimplemented to enable various Model class methods to work
|
@@ -58,71 +62,100 @@ module Cosmos
|
|
58
62
|
|
59
63
|
# Called by the PluginsController to parse the plugin variables
|
60
64
|
# Doesn't actaully create the plugin during the phase
|
61
|
-
def self.install_phase1(gem_file_path, existing_variables
|
62
|
-
|
63
|
-
|
64
|
-
# Load gem to internal gem server
|
65
|
-
Cosmos::GemModel.put(gem_file_path, gem_install: false, scope: scope)
|
66
|
-
|
67
|
-
# Extract gem and process plugin.txt to determine what VARIABLEs need to be filled in
|
68
|
-
pkg = Gem::Package.new(gem_file_path)
|
65
|
+
def self.install_phase1(gem_file_path, existing_variables: nil, existing_plugin_txt_lines: nil, process_existing: false, scope:, validate_only: false)
|
66
|
+
gem_name = File.basename(gem_file_path).split("__")[0]
|
69
67
|
|
70
68
|
temp_dir = Dir.mktmpdir
|
69
|
+
tf = nil
|
71
70
|
begin
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
71
|
+
if File.exists?(gem_file_path)
|
72
|
+
# Load gem to internal gem server
|
73
|
+
Cosmos::GemModel.put(gem_file_path, gem_install: false, scope: scope) unless validate_only
|
74
|
+
else
|
75
|
+
gem_file_path = Cosmos::GemModel.get(temp_dir, gem_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Extract gem and process plugin.txt to determine what VARIABLEs need to be filled in
|
79
|
+
pkg = Gem::Package.new(gem_file_path)
|
80
|
+
|
81
|
+
if existing_plugin_txt_lines and process_existing
|
82
|
+
# This is only used in cosmos load when everything is known
|
83
|
+
plugin_txt_lines = existing_plugin_txt_lines
|
84
|
+
file_data = existing_plugin_txt_lines.join("\n")
|
85
|
+
tf = Tempfile.new("plugin.txt")
|
86
|
+
tf.write(file_data)
|
87
|
+
tf.close
|
88
|
+
plugin_txt_path = tf.path
|
89
|
+
else
|
90
|
+
# Otherwise we always process the new and return both
|
91
|
+
pkg.extract_files(temp_dir)
|
92
|
+
plugin_txt_path = File.join(temp_dir, 'plugin.txt')
|
93
|
+
plugin_text = File.read(plugin_txt_path)
|
94
|
+
plugin_txt_lines = []
|
95
|
+
plugin_text.each_line do |line|
|
96
|
+
plugin_txt_lines << line.chomp
|
95
97
|
end
|
98
|
+
end
|
99
|
+
|
100
|
+
parser = Cosmos::ConfigParser.new("http://cosmosc2.com")
|
96
101
|
|
97
|
-
|
98
|
-
|
102
|
+
# Phase 1 Gather Variables
|
103
|
+
variables = {}
|
104
|
+
parser.parse_file(plugin_txt_path,
|
105
|
+
false,
|
106
|
+
true,
|
107
|
+
false) do |keyword, params|
|
108
|
+
case keyword
|
109
|
+
when 'VARIABLE'
|
110
|
+
usage = "#{keyword} <Variable Name> <Default Value>"
|
111
|
+
parser.verify_num_parameters(2, nil, usage)
|
112
|
+
variable_name = params[0]
|
113
|
+
value = params[1..-1].join(" ")
|
114
|
+
variables[variable_name] = value
|
115
|
+
if existing_variables && existing_variables.key?(variable_name)
|
116
|
+
variables[variable_name] = existing_variables[variable_name]
|
117
|
+
end
|
118
|
+
# Ignore everything else during phase 1
|
119
|
+
end
|
99
120
|
end
|
121
|
+
|
122
|
+
model = PluginModel.new(name: gem_name, variables: variables, plugin_txt_lines: plugin_txt_lines, scope: scope)
|
123
|
+
result = model.as_json
|
124
|
+
result['existing_plugin_txt_lines'] = existing_plugin_txt_lines if existing_plugin_txt_lines and not process_existing and existing_plugin_txt_lines != result['plugin_txt_lines']
|
125
|
+
return result
|
100
126
|
ensure
|
101
127
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
128
|
+
tf.unlink if tf
|
102
129
|
end
|
103
130
|
end
|
104
131
|
|
105
132
|
# Called by the PluginsController to create the plugin
|
106
133
|
# Because this uses ERB it must be run in a seperate process from the API to
|
107
134
|
# prevent corruption and single require problems in the current proces
|
108
|
-
def self.install_phase2(
|
135
|
+
def self.install_phase2(plugin_hash, scope:, validate_only: false)
|
109
136
|
rubys3_client = Aws::S3::Client.new
|
110
137
|
|
111
138
|
# Ensure config bucket exists
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
139
|
+
unless validate_only
|
140
|
+
begin
|
141
|
+
rubys3_client.head_bucket(bucket: 'config')
|
142
|
+
rescue Aws::S3::Errors::NotFound
|
143
|
+
rubys3_client.create_bucket(bucket: 'config')
|
144
|
+
end
|
116
145
|
end
|
117
146
|
|
118
147
|
# Register plugin to aid in uninstall if install fails
|
119
|
-
|
120
|
-
plugin_model.
|
148
|
+
plugin_hash.delete("existing_plugin_txt_lines")
|
149
|
+
plugin_model = PluginModel.new(**(plugin_hash.transform_keys(&:to_sym)), scope: scope)
|
150
|
+
plugin_model.create unless validate_only
|
121
151
|
|
122
152
|
temp_dir = Dir.mktmpdir
|
123
153
|
begin
|
154
|
+
tf = nil
|
155
|
+
|
124
156
|
# Get the gem from local gem server
|
125
|
-
|
157
|
+
gem_name = plugin_hash['name'].split("__")[0]
|
158
|
+
gem_file_path = Cosmos::GemModel.get(temp_dir, gem_name)
|
126
159
|
|
127
160
|
# Actually install the gem now (slow)
|
128
161
|
Cosmos::GemModel.install(gem_file_path, scope: scope)
|
@@ -133,6 +166,11 @@ module Cosmos
|
|
133
166
|
pkg = Gem::Package.new(gem_file_path)
|
134
167
|
needs_dependencies = pkg.spec.runtime_dependencies.length > 0
|
135
168
|
pkg.extract_files(gem_path)
|
169
|
+
needs_dependencies = true if Dir.exist?(File.join(gem_path, 'lib'))
|
170
|
+
if needs_dependencies
|
171
|
+
plugin_model.needs_dependencies = true
|
172
|
+
plugin_model.update
|
173
|
+
end
|
136
174
|
|
137
175
|
# Temporarily add all lib folders from the gem to the end of the load path
|
138
176
|
load_dirs = []
|
@@ -145,7 +183,12 @@ module Cosmos
|
|
145
183
|
end
|
146
184
|
|
147
185
|
# Process plugin.txt file
|
148
|
-
|
186
|
+
file_data = plugin_hash['plugin_txt_lines'].join("\n")
|
187
|
+
tf = Tempfile.new("plugin.txt")
|
188
|
+
tf.write(file_data)
|
189
|
+
tf.close
|
190
|
+
plugin_txt_path = tf.path
|
191
|
+
variables = plugin_hash['variables']
|
149
192
|
if File.exist?(plugin_txt_path)
|
150
193
|
parser = Cosmos::ConfigParser.new("http://cosmosc2.com")
|
151
194
|
|
@@ -156,8 +199,8 @@ module Cosmos
|
|
156
199
|
# Ignore during phase 2
|
157
200
|
when 'TARGET', 'INTERFACE', 'ROUTER', 'MICROSERVICE', 'TOOL', 'WIDGET'
|
158
201
|
if current_model
|
159
|
-
current_model.create
|
160
|
-
current_model.deploy(gem_path, variables)
|
202
|
+
current_model.create unless validate_only
|
203
|
+
current_model.deploy(gem_path, variables, validate_only: validate_only)
|
161
204
|
current_model = nil
|
162
205
|
end
|
163
206
|
current_model = Cosmos.const_get((keyword.capitalize + 'Model').intern).handle_config(parser, keyword, params, plugin: plugin_model.name, needs_dependencies: needs_dependencies, scope: scope)
|
@@ -170,8 +213,8 @@ module Cosmos
|
|
170
213
|
end
|
171
214
|
end
|
172
215
|
if current_model
|
173
|
-
current_model.create
|
174
|
-
current_model.deploy(gem_path, variables)
|
216
|
+
current_model.create unless validate_only
|
217
|
+
current_model.deploy(gem_path, variables, validate_only: validate_only)
|
175
218
|
current_model = nil
|
176
219
|
end
|
177
220
|
end
|
@@ -182,21 +225,28 @@ module Cosmos
|
|
182
225
|
end
|
183
226
|
rescue => err
|
184
227
|
# Install failed - need to cleanup
|
185
|
-
plugin_model.destroy
|
228
|
+
plugin_model.destroy unless validate_only
|
186
229
|
raise err
|
187
230
|
ensure
|
188
231
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
232
|
+
tf.unlink if tf
|
189
233
|
end
|
234
|
+
|
235
|
+
return plugin_model.as_json
|
190
236
|
end
|
191
237
|
|
192
238
|
def initialize(
|
193
239
|
name:,
|
194
240
|
variables: {},
|
241
|
+
plugin_txt_lines: [],
|
242
|
+
needs_dependencies: false,
|
195
243
|
updated_at: nil,
|
196
244
|
scope:
|
197
245
|
)
|
198
246
|
super("#{scope}__#{PRIMARY_KEY}", name: name, updated_at: updated_at, scope: scope)
|
199
247
|
@variables = variables
|
248
|
+
@plugin_txt_lines = plugin_txt_lines
|
249
|
+
@needs_dependencies = ConfigParser.handle_true_false(needs_dependencies)
|
200
250
|
end
|
201
251
|
|
202
252
|
def create(update: false, force: false)
|
@@ -208,6 +258,8 @@ module Cosmos
|
|
208
258
|
{
|
209
259
|
'name' => @name,
|
210
260
|
'variables' => @variables,
|
261
|
+
'plugin_txt_lines' => @plugin_txt_lines,
|
262
|
+
'needs_dependencies' => @needs_dependencies,
|
211
263
|
'updated_at' => @updated_at
|
212
264
|
}
|
213
265
|
end
|
@@ -220,5 +272,13 @@ module Cosmos
|
|
220
272
|
end
|
221
273
|
end
|
222
274
|
end
|
275
|
+
|
276
|
+
# Reinstall
|
277
|
+
def restore
|
278
|
+
plugin_hash = self.as_json
|
279
|
+
plugin_hash['name'] = plugin_hash['name'].split("__")[0]
|
280
|
+
Cosmos::PluginModel.install_phase2(plugin_hash, scope: @scope)
|
281
|
+
@destroyed = false
|
282
|
+
end
|
223
283
|
end
|
224
284
|
end
|
@@ -119,6 +119,7 @@ module Cosmos
|
|
119
119
|
def create(update: false)
|
120
120
|
validate_start(update: update)
|
121
121
|
@updated_at = Time.now.to_nsec_from_epoch
|
122
|
+
SortedModel.destroy(scope: @scope, start: update) if update
|
122
123
|
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
123
124
|
if update
|
124
125
|
notify(kind: 'updated')
|
@@ -129,8 +130,9 @@ module Cosmos
|
|
129
130
|
|
130
131
|
# Update the Redis hash at primary_key
|
131
132
|
def update(start:)
|
133
|
+
orig_start = @start
|
132
134
|
@start = start
|
133
|
-
create(update:
|
135
|
+
create(update: orig_start)
|
134
136
|
end
|
135
137
|
|
136
138
|
# destroy the activity from the redis database
|
@@ -22,6 +22,7 @@ require 'cosmos/models/model'
|
|
22
22
|
require 'cosmos/models/cvt_model'
|
23
23
|
require 'cosmos/models/microservice_model'
|
24
24
|
require 'cosmos/topics/limits_event_topic'
|
25
|
+
require 'cosmos/topics/config_topic'
|
25
26
|
require 'cosmos/system'
|
26
27
|
require 'cosmos/utilities/s3'
|
27
28
|
require 'cosmos/utilities/zip'
|
@@ -360,7 +361,7 @@ module Cosmos
|
|
360
361
|
return nil
|
361
362
|
end
|
362
363
|
|
363
|
-
def deploy(gem_path, variables)
|
364
|
+
def deploy(gem_path, variables, validate_only: false)
|
364
365
|
rubys3_client = Aws::S3::Client.new
|
365
366
|
variables["target_name"] = @name
|
366
367
|
start_path = "/targets/#{@folder_name}/"
|
@@ -389,14 +390,23 @@ module Cosmos
|
|
389
390
|
FileUtils.mkdir_p(File.dirname(local_path))
|
390
391
|
File.open(local_path, 'wb') { |file| file.write(data) }
|
391
392
|
found = true
|
392
|
-
rubys3_client.put_object(bucket: 'config', key: key, body: data)
|
393
|
+
rubys3_client.put_object(bucket: 'config', key: key, body: data) unless validate_only
|
393
394
|
end
|
394
395
|
raise "No target files found at #{target_path}" unless found
|
395
396
|
|
396
397
|
target_folder = File.join(temp_dir, @name)
|
397
|
-
|
398
|
-
system =
|
399
|
-
|
398
|
+
# Build a System for just this target
|
399
|
+
system = System.new([@name], temp_dir)
|
400
|
+
if variables["xtce_output"]
|
401
|
+
puts "Converting target #{@name} to .xtce files in #{variables["xtce_output"]}/#{@name}"
|
402
|
+
system.packet_config.to_xtce(variables["xtce_output"])
|
403
|
+
end
|
404
|
+
unless validate_only
|
405
|
+
build_target_archive(rubys3_client, temp_dir, target_folder)
|
406
|
+
system = update_store(system)
|
407
|
+
deploy_microservices(gem_path, variables, system)
|
408
|
+
ConfigTopic.write({ kind: 'created', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
409
|
+
end
|
400
410
|
ensure
|
401
411
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
402
412
|
end
|
@@ -430,6 +440,7 @@ module Cosmos
|
|
430
440
|
model = MicroserviceModel.get_model(name: "#{@scope}__#{type}__#{@name}", scope: @scope)
|
431
441
|
model.destroy if model
|
432
442
|
end
|
443
|
+
ConfigTopic.write({ kind: 'deleted', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
433
444
|
end
|
434
445
|
|
435
446
|
##################################################
|
@@ -497,9 +508,7 @@ module Cosmos
|
|
497
508
|
end
|
498
509
|
end
|
499
510
|
|
500
|
-
def update_store(
|
501
|
-
# Build a System for just this target
|
502
|
-
system = System.new([@name], temp_dir)
|
511
|
+
def update_store(system)
|
503
512
|
target = system.targets[@name]
|
504
513
|
|
505
514
|
# Add in the information from the target and update
|
@@ -606,7 +615,7 @@ module Cosmos
|
|
606
615
|
],
|
607
616
|
topics: command_topic_list,
|
608
617
|
target_names: [@name],
|
609
|
-
plugin: plugin,
|
618
|
+
plugin: @plugin,
|
610
619
|
needs_dependencies: @needs_dependencies,
|
611
620
|
scope: @scope
|
612
621
|
)
|
@@ -629,7 +638,7 @@ module Cosmos
|
|
629
638
|
],
|
630
639
|
topics: decom_command_topic_list,
|
631
640
|
target_names: [@name],
|
632
|
-
plugin: plugin,
|
641
|
+
plugin: @plugin,
|
633
642
|
needs_dependencies: @needs_dependencies,
|
634
643
|
scope: @scope
|
635
644
|
)
|
@@ -654,7 +663,7 @@ module Cosmos
|
|
654
663
|
],
|
655
664
|
topics: packet_topic_list,
|
656
665
|
target_names: [@name],
|
657
|
-
plugin: plugin,
|
666
|
+
plugin: @plugin,
|
658
667
|
needs_dependencies: @needs_dependencies,
|
659
668
|
scope: @scope
|
660
669
|
)
|
@@ -677,7 +686,7 @@ module Cosmos
|
|
677
686
|
],
|
678
687
|
topics: decom_topic_list,
|
679
688
|
target_names: [@name],
|
680
|
-
plugin: plugin,
|
689
|
+
plugin: @plugin,
|
681
690
|
needs_dependencies: @needs_dependencies,
|
682
691
|
scope: @scope
|
683
692
|
)
|
@@ -694,7 +703,7 @@ module Cosmos
|
|
694
703
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
695
704
|
topics: packet_topic_list,
|
696
705
|
target_names: [@name],
|
697
|
-
plugin: plugin,
|
706
|
+
plugin: @plugin,
|
698
707
|
needs_dependencies: @needs_dependencies,
|
699
708
|
scope: @scope
|
700
709
|
)
|
@@ -710,7 +719,7 @@ module Cosmos
|
|
710
719
|
cmd: ["ruby", "reducer_microservice.rb", microservice_name],
|
711
720
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
712
721
|
topics: decom_topic_list,
|
713
|
-
plugin: plugin,
|
722
|
+
plugin: @plugin,
|
714
723
|
needs_dependencies: @needs_dependencies,
|
715
724
|
scope: @scope
|
716
725
|
)
|
@@ -727,7 +736,7 @@ module Cosmos
|
|
727
736
|
name: microservice_name,
|
728
737
|
cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
|
729
738
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
730
|
-
plugin: plugin,
|
739
|
+
plugin: @plugin,
|
731
740
|
scope: @scope
|
732
741
|
)
|
733
742
|
microservice.create
|
@@ -209,13 +209,11 @@ module Cosmos
|
|
209
209
|
return nil
|
210
210
|
end
|
211
211
|
|
212
|
-
def deploy(gem_path, variables)
|
212
|
+
def deploy(gem_path, variables, validate_only: false)
|
213
213
|
return unless @folder_name
|
214
214
|
|
215
|
-
rubys3_client = Aws::S3::Client.new
|
216
|
-
|
217
215
|
# Ensure tools bucket exists
|
218
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
216
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
219
217
|
|
220
218
|
variables["tool_name"] = @name
|
221
219
|
start_path = "/tools/#{@folder_name}/"
|
@@ -223,16 +221,17 @@ module Cosmos
|
|
223
221
|
next if filename == '.' or filename == '..' or File.directory?(filename)
|
224
222
|
|
225
223
|
key = filename.split(gem_path + '/tools/')[-1]
|
226
|
-
|
227
224
|
extension = filename.split('.')[-1]
|
228
225
|
content_type = Rack::Mime.mime_type(".#{extension}")
|
229
226
|
|
230
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
231
|
-
|
232
227
|
# Load tool files
|
233
228
|
data = File.read(filename, mode: "rb")
|
234
229
|
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
235
|
-
|
230
|
+
unless validate_only
|
231
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
232
|
+
Aws::S3::Client.new.put_object(bucket: 'tools', content_type: content_type, cache_control: cache_control, key: key, body: data)
|
233
|
+
ConfigTopic.write({ kind: 'created', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
234
|
+
end
|
236
235
|
end
|
237
236
|
end
|
238
237
|
|
@@ -242,6 +241,7 @@ module Cosmos
|
|
242
241
|
prefix = "#{@folder_name}/"
|
243
242
|
rubys3_client.list_objects(bucket: 'tools', prefix: prefix).contents.each do |object|
|
244
243
|
rubys3_client.delete_object(bucket: 'tools', key: object.key)
|
244
|
+
ConfigTopic.write({ kind: 'deleted', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
245
245
|
end
|
246
246
|
end
|
247
247
|
end
|
@@ -108,25 +108,25 @@ module Cosmos
|
|
108
108
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Widget: #{keyword} #{parameters.join(" ")}")
|
109
109
|
end
|
110
110
|
|
111
|
-
def deploy(gem_path, variables)
|
112
|
-
rubys3_client = Aws::S3::Client.new
|
113
|
-
|
111
|
+
def deploy(gem_path, variables, validate_only: false)
|
114
112
|
# Ensure tools bucket exists
|
115
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
113
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
116
114
|
|
117
115
|
filename = gem_path + "/tools/widgets/" + @full_name + '/' + @filename
|
118
116
|
|
119
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
120
|
-
|
121
117
|
# Load widget file
|
122
118
|
data = File.read(filename, mode: "rb")
|
123
119
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
124
120
|
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
125
121
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
122
|
+
unless validate_only
|
123
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
124
|
+
# TODO: support widgets that aren't just a single js file (and its associated map file)
|
125
|
+
rubys3_client = Aws::S3::Client.new
|
126
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/javascript', cache_control: cache_control, key: @s3_key, body: data)
|
127
|
+
data = File.read(filename + '.map', mode: "rb")
|
128
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/json', cache_control: cache_control, key: @s3_key + '.map', body: data)
|
129
|
+
end
|
130
130
|
end
|
131
131
|
|
132
132
|
def undeploy
|
@@ -98,7 +98,7 @@ module Cosmos
|
|
98
98
|
# @param buffer [String] String buffer to hold the packet data
|
99
99
|
# @param item_class [Class] Class used to instantiate items (Must be a
|
100
100
|
# subclass of PacketItem)
|
101
|
-
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer =
|
101
|
+
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer = nil, item_class = PacketItem)
|
102
102
|
super(default_endianness, buffer, item_class)
|
103
103
|
# Explictly call the defined setter methods
|
104
104
|
self.target_name = target_name
|
@@ -66,7 +66,7 @@ module Cosmos
|
|
66
66
|
# @param buffer [String] Buffer used to store the structure
|
67
67
|
# @param item_class [Class] Class used to instantiate new structure items.
|
68
68
|
# Must be StructureItem or one of its subclasses.
|
69
|
-
def initialize(default_endianness = BinaryAccessor::HOST_ENDIANNESS, buffer =
|
69
|
+
def initialize(default_endianness = BinaryAccessor::HOST_ENDIANNESS, buffer = nil, item_class = StructureItem)
|
70
70
|
if (default_endianness == :BIG_ENDIAN) || (default_endianness == :LITTLE_ENDIAN)
|
71
71
|
@default_endianness = default_endianness
|
72
72
|
if buffer
|
@@ -102,14 +102,11 @@ module Cosmos
|
|
102
102
|
def read_item(item, value_type = :RAW, buffer = @buffer)
|
103
103
|
return nil if item.data_type == :DERIVED
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
|
110
|
-
end
|
105
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
106
|
+
if item.array_size
|
107
|
+
return BinaryAccessor.read_array(item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness)
|
111
108
|
else
|
112
|
-
|
109
|
+
return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
@@ -117,9 +114,8 @@ module Cosmos
|
|
117
114
|
#
|
118
115
|
# @return [Integer] Size of the buffer in bytes
|
119
116
|
def length
|
120
|
-
|
121
|
-
|
122
|
-
return 0
|
117
|
+
allocate_buffer_if_needed()
|
118
|
+
return @buffer.length
|
123
119
|
end
|
124
120
|
|
125
121
|
# Resize the buffer at least the defined length of the structure
|
@@ -129,12 +125,23 @@ module Cosmos
|
|
129
125
|
if @buffer.length < @defined_length
|
130
126
|
@buffer << (ZERO_STRING * (@defined_length - @buffer.length))
|
131
127
|
end
|
128
|
+
else
|
129
|
+
allocate_buffer_if_needed()
|
132
130
|
end
|
133
131
|
|
134
132
|
return self
|
135
133
|
end
|
136
134
|
end
|
137
135
|
|
136
|
+
# Allocate a buffer if not available
|
137
|
+
def allocate_buffer_if_needed
|
138
|
+
unless @buffer
|
139
|
+
@buffer = ZERO_STRING * @defined_length
|
140
|
+
@buffer.force_encoding(ASCII_8BIT_STRING)
|
141
|
+
end
|
142
|
+
return @buffer
|
143
|
+
end
|
144
|
+
|
138
145
|
# Indicates if any items have been defined for this structure
|
139
146
|
# @return [TrueClass or FalseClass]
|
140
147
|
def defined?
|
@@ -340,14 +347,11 @@ module Cosmos
|
|
340
347
|
# parameter to check whether to perform conversions on the item.
|
341
348
|
# @param buffer [String] The binary buffer to write the value to
|
342
349
|
def write_item(item, value, value_type = :RAW, buffer = @buffer)
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
else
|
347
|
-
BinaryAccessor.write(value, item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness, item.overflow)
|
348
|
-
end
|
350
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
351
|
+
if item.array_size
|
352
|
+
BinaryAccessor.write_array(value, item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness, item.overflow)
|
349
353
|
else
|
350
|
-
|
354
|
+
BinaryAccessor.write(value, item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness, item.overflow)
|
351
355
|
end
|
352
356
|
end
|
353
357
|
|
@@ -432,14 +436,11 @@ module Cosmos
|
|
432
436
|
# @param copy [TrueClass/FalseClass] Whether to copy the buffer
|
433
437
|
# @return [String] Data buffer backing the structure
|
434
438
|
def buffer(copy = true)
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
else
|
439
|
-
return @buffer
|
440
|
-
end
|
439
|
+
local_buffer = allocate_buffer_if_needed()
|
440
|
+
if copy
|
441
|
+
return local_buffer.dup
|
441
442
|
else
|
442
|
-
return
|
443
|
+
return local_buffer
|
443
444
|
end
|
444
445
|
end
|
445
446
|
|
@@ -525,15 +526,11 @@ module Cosmos
|
|
525
526
|
module MethodMissing
|
526
527
|
# Method missing provides reading/writing item values as if they were methods to the class
|
527
528
|
def method_missing(name, value = nil)
|
528
|
-
if
|
529
|
-
|
530
|
-
|
531
|
-
return write(name.to_s[0..-2], value)
|
532
|
-
else
|
533
|
-
return read(name.to_s)
|
534
|
-
end
|
529
|
+
if value
|
530
|
+
# Strip off the equals sign before looking up the item
|
531
|
+
return write(name.to_s[0..-2], value)
|
535
532
|
else
|
536
|
-
|
533
|
+
return read(name.to_s)
|
537
534
|
end
|
538
535
|
end
|
539
536
|
end
|
@@ -42,6 +42,9 @@ module Cosmos
|
|
42
42
|
# @param start [Time] Metadata time value, if nil will be current time
|
43
43
|
# @return The result of the method call.
|
44
44
|
def set_metadata(metadata, color: nil, start: nil)
|
45
|
+
unless metadata.is_a?(Hash)
|
46
|
+
raise "metadata must be a Hash: #{metadata} is a #{metadata.class}"
|
47
|
+
end
|
45
48
|
color = color.nil? ? '#003784' : color
|
46
49
|
data = { color: color, metadata: metadata }
|
47
50
|
data[:start] = start.iso8601 unless start.nil?
|
@@ -52,12 +55,20 @@ module Cosmos
|
|
52
55
|
|
53
56
|
# Updates the metadata
|
54
57
|
#
|
55
|
-
# @param start [Integer] Metadata time value as integer seconds from epoch
|
56
58
|
# @param metadata [Hash<Symbol, Variable>] A hash of metadata
|
57
59
|
# @param color [String] Events color to show on Calendar tool, if nil will be blue
|
60
|
+
# @param start [Integer] Metadata time value as integer seconds from epoch
|
58
61
|
# @return The result of the method call.
|
59
|
-
def update_metadata(
|
62
|
+
def update_metadata(metadata, color: nil, start: nil)
|
63
|
+
unless metadata.is_a?(Hash)
|
64
|
+
raise "metadata must be a Hash: #{metadata} is a #{metadata.class}"
|
65
|
+
end
|
60
66
|
color = color.nil? ? '#003784' : color
|
67
|
+
if start == nil
|
68
|
+
existing = get_metadata()
|
69
|
+
start = existing['start']
|
70
|
+
metadata = existing['metadata'].merge(metadata)
|
71
|
+
end
|
61
72
|
data = { :color => color, :metadata => metadata }
|
62
73
|
data[:start] = Time.at(start).iso8601
|
63
74
|
response = $api_server.request('put', "/cosmos-api/metadata/#{start}", data: data, json: true)
|