openc3 7.2.1 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (502) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Guardfile +0 -0
  4. data/LICENSE.md +0 -0
  5. data/README.md +0 -0
  6. data/Rakefile +0 -0
  7. data/bin/openc3cli +235 -6
  8. data/bin/pipinstall +5 -4
  9. data/bin/pipuninstall +5 -1
  10. data/bin/uvinstall +156 -0
  11. data/data/config/_array_params.yaml +0 -0
  12. data/data/config/_canvas_values.yaml +0 -0
  13. data/data/config/_graph_params.yaml +0 -0
  14. data/data/config/_id_items.yaml +0 -0
  15. data/data/config/_id_params.yaml +0 -0
  16. data/data/config/_interfaces.yaml +0 -0
  17. data/data/config/_items.yaml +0 -0
  18. data/data/config/_params.yaml +0 -0
  19. data/data/config/command.yaml +0 -0
  20. data/data/config/command_modifiers.yaml +2 -0
  21. data/data/config/command_telemetry.yaml +0 -0
  22. data/data/config/conversions.yaml +0 -0
  23. data/data/config/graph_settings.yaml +0 -0
  24. data/data/config/interface_modifiers.yaml +103 -1
  25. data/data/config/item_modifiers.yaml +2 -1
  26. data/data/config/microservice.yaml +9 -2
  27. data/data/config/param_item_modifiers.yaml +0 -0
  28. data/data/config/parameter_modifiers.yaml +0 -0
  29. data/data/config/plugins.yaml +0 -0
  30. data/data/config/processors.yaml +0 -0
  31. data/data/config/protocols.yaml +0 -0
  32. data/data/config/screen.yaml +2 -1
  33. data/data/config/settings.yaml +0 -0
  34. data/data/config/table_manager.yaml +0 -0
  35. data/data/config/table_parameter_modifiers.yaml +0 -0
  36. data/data/config/target.yaml +21 -0
  37. data/data/config/target_config.yaml +0 -0
  38. data/data/config/telemetry.yaml +0 -0
  39. data/data/config/telemetry_modifiers.yaml +2 -0
  40. data/data/config/tool.yaml +3 -1
  41. data/data/config/unknown.yaml +0 -0
  42. data/data/config/widgets.yaml +22 -3
  43. data/data/xtce_schemas/SpaceSystem_20180204.xsd +5918 -0
  44. data/data/xtce_schemas/xml.xsd +116 -0
  45. data/ext/openc3/ext/array/array.c +0 -0
  46. data/ext/openc3/ext/array/extconf.rb +0 -0
  47. data/ext/openc3/ext/buffered_file/buffered_file.c +0 -0
  48. data/ext/openc3/ext/buffered_file/extconf.rb +0 -0
  49. data/ext/openc3/ext/burst_protocol/burst_protocol.c +6 -0
  50. data/ext/openc3/ext/burst_protocol/extconf.rb +0 -0
  51. data/ext/openc3/ext/config_parser/config_parser.c +0 -0
  52. data/ext/openc3/ext/config_parser/extconf.rb +0 -0
  53. data/ext/openc3/ext/crc/crc.c +0 -0
  54. data/ext/openc3/ext/crc/extconf.rb +0 -0
  55. data/ext/openc3/ext/openc3_io/extconf.rb +0 -0
  56. data/ext/openc3/ext/openc3_io/openc3_io.c +0 -0
  57. data/ext/openc3/ext/packet/extconf.rb +0 -0
  58. data/ext/openc3/ext/packet/packet.c +0 -0
  59. data/ext/openc3/ext/platform/extconf.rb +0 -0
  60. data/ext/openc3/ext/platform/platform.c +4 -1
  61. data/ext/openc3/ext/polynomial_conversion/extconf.rb +0 -0
  62. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +0 -0
  63. data/ext/openc3/ext/string/extconf.rb +0 -0
  64. data/ext/openc3/ext/string/string.c +0 -0
  65. data/ext/openc3/ext/structure/structure.c +49 -17
  66. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +0 -0
  67. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +0 -0
  68. data/ext/openc3/ext/telemetry/extconf.rb +0 -0
  69. data/ext/openc3/ext/telemetry/telemetry.c +1 -1
  70. data/lib/cosmos.rb +0 -0
  71. data/lib/cosmosc2.rb +0 -0
  72. data/lib/openc3/accessors/accessor.rb +0 -0
  73. data/lib/openc3/accessors/binary_accessor.rb +63 -9
  74. data/lib/openc3/accessors/cbor_accessor.rb +0 -0
  75. data/lib/openc3/accessors/form_accessor.rb +0 -0
  76. data/lib/openc3/accessors/html_accessor.rb +0 -0
  77. data/lib/openc3/accessors/http_accessor.rb +0 -0
  78. data/lib/openc3/accessors/json_accessor.rb +0 -0
  79. data/lib/openc3/accessors/template_accessor.rb +2 -2
  80. data/lib/openc3/accessors/xml_accessor.rb +0 -0
  81. data/lib/openc3/accessors.rb +0 -0
  82. data/lib/openc3/api/README.md +0 -0
  83. data/lib/openc3/api/api.rb +0 -0
  84. data/lib/openc3/api/authorized_api.rb +0 -0
  85. data/lib/openc3/api/calendar_api.rb +0 -0
  86. data/lib/openc3/api/cmd_api.rb +1 -1
  87. data/lib/openc3/api/config_api.rb +0 -0
  88. data/lib/openc3/api/interface_api.rb +2 -2
  89. data/lib/openc3/api/limits_api.rb +27 -13
  90. data/lib/openc3/api/metrics_api.rb +1 -1
  91. data/lib/openc3/api/offline_access_api.rb +1 -1
  92. data/lib/openc3/api/router_api.rb +3 -3
  93. data/lib/openc3/api/settings_api.rb +22 -18
  94. data/lib/openc3/api/stash_api.rb +1 -1
  95. data/lib/openc3/api/target_api.rb +0 -0
  96. data/lib/openc3/api/tlm_api.rb +5 -4
  97. data/lib/openc3/bridge/bridge.rb +0 -0
  98. data/lib/openc3/bridge/bridge_config.rb +0 -0
  99. data/lib/openc3/bridge/bridge_interface_thread.rb +0 -0
  100. data/lib/openc3/bridge/bridge_router_thread.rb +0 -0
  101. data/lib/openc3/ccsds/ccsds_packet.rb +0 -0
  102. data/lib/openc3/ccsds/ccsds_parser.rb +0 -0
  103. data/lib/openc3/config/config_parser.rb +78 -17
  104. data/lib/openc3/config/meta_config_parser.rb +0 -0
  105. data/lib/openc3/conversions/bit_reverse_conversion.rb +0 -0
  106. data/lib/openc3/conversions/conversion.rb +0 -0
  107. data/lib/openc3/conversions/generic_conversion.rb +0 -0
  108. data/lib/openc3/conversions/ip_read_conversion.rb +0 -0
  109. data/lib/openc3/conversions/ip_write_conversion.rb +0 -0
  110. data/lib/openc3/conversions/object_read_conversion.rb +0 -0
  111. data/lib/openc3/conversions/object_write_conversion.rb +0 -0
  112. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +0 -0
  113. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +0 -0
  114. data/lib/openc3/conversions/polynomial_conversion.rb +0 -0
  115. data/lib/openc3/conversions/processor_conversion.rb +0 -0
  116. data/lib/openc3/conversions/received_count_conversion.rb +0 -0
  117. data/lib/openc3/conversions/received_time_formatted_conversion.rb +0 -0
  118. data/lib/openc3/conversions/received_time_seconds_conversion.rb +0 -0
  119. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +0 -0
  120. data/lib/openc3/conversions/unix_time_conversion.rb +0 -0
  121. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +0 -0
  122. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +0 -0
  123. data/lib/openc3/conversions.rb +0 -0
  124. data/lib/openc3/core_ext/array.rb +0 -0
  125. data/lib/openc3/core_ext/binding.rb +0 -0
  126. data/lib/openc3/core_ext/class.rb +0 -0
  127. data/lib/openc3/core_ext/exception.rb +0 -0
  128. data/lib/openc3/core_ext/faraday.rb +0 -0
  129. data/lib/openc3/core_ext/file.rb +0 -0
  130. data/lib/openc3/core_ext/io.rb +0 -0
  131. data/lib/openc3/core_ext/kernel.rb +0 -0
  132. data/lib/openc3/core_ext/math.rb +0 -0
  133. data/lib/openc3/core_ext/matrix.rb +0 -0
  134. data/lib/openc3/core_ext/objectspace.rb +0 -0
  135. data/lib/openc3/core_ext/openc3_io.rb +0 -0
  136. data/lib/openc3/core_ext/range.rb +0 -0
  137. data/lib/openc3/core_ext/socket.rb +0 -0
  138. data/lib/openc3/core_ext/string.rb +0 -0
  139. data/lib/openc3/core_ext/stringio.rb +0 -0
  140. data/lib/openc3/core_ext/tempfile.rb +0 -0
  141. data/lib/openc3/core_ext/time.rb +0 -0
  142. data/lib/openc3/core_ext.rb +0 -0
  143. data/lib/openc3/ext/.keep +0 -0
  144. data/lib/openc3/interfaces/file_interface.rb +0 -0
  145. data/lib/openc3/interfaces/http_client_interface.rb +1 -1
  146. data/lib/openc3/interfaces/http_server_interface.rb +0 -0
  147. data/lib/openc3/interfaces/interface.rb +5 -4
  148. data/lib/openc3/interfaces/mqtt_interface.rb +0 -0
  149. data/lib/openc3/interfaces/mqtt_stream_interface.rb +2 -0
  150. data/lib/openc3/interfaces/protocols/burst_protocol.rb +27 -0
  151. data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +0 -0
  152. data/lib/openc3/interfaces/protocols/cobs_protocol.rb +0 -0
  153. data/lib/openc3/interfaces/protocols/crc_protocol.rb +0 -0
  154. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +0 -0
  155. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +0 -0
  156. data/lib/openc3/interfaces/protocols/length_protocol.rb +7 -0
  157. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +7 -0
  158. data/lib/openc3/interfaces/protocols/protocol.rb +4 -4
  159. data/lib/openc3/interfaces/protocols/slip_protocol.rb +0 -0
  160. data/lib/openc3/interfaces/protocols/template_protocol.rb +2 -2
  161. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +0 -0
  162. data/lib/openc3/interfaces/serial_interface.rb +2 -0
  163. data/lib/openc3/interfaces/simulated_target_interface.rb +0 -0
  164. data/lib/openc3/interfaces/stream_interface.rb +0 -0
  165. data/lib/openc3/interfaces/tcpip_client_interface.rb +2 -0
  166. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -0
  167. data/lib/openc3/interfaces/udp_interface.rb +16 -5
  168. data/lib/openc3/interfaces.rb +0 -0
  169. data/lib/openc3/io/buffered_file.rb +0 -0
  170. data/lib/openc3/io/io_multiplexer.rb +0 -0
  171. data/lib/openc3/io/json_api.rb +3 -2
  172. data/lib/openc3/io/json_api_object.rb +0 -0
  173. data/lib/openc3/io/json_drb.rb +44 -12
  174. data/lib/openc3/io/json_drb_object.rb +0 -0
  175. data/lib/openc3/io/json_drb_rack.rb +0 -0
  176. data/lib/openc3/io/json_rpc.rb +0 -2
  177. data/lib/openc3/io/posix_serial_driver.rb +0 -0
  178. data/lib/openc3/io/serial_driver.rb +0 -0
  179. data/lib/openc3/io/stderr.rb +0 -0
  180. data/lib/openc3/io/stdout.rb +0 -0
  181. data/lib/openc3/io/udp_sockets.rb +38 -8
  182. data/lib/openc3/io/win32_serial_driver.rb +1 -0
  183. data/lib/openc3/logs/buffered_packet_log_reader.rb +0 -0
  184. data/lib/openc3/logs/buffered_packet_log_writer.rb +0 -0
  185. data/lib/openc3/logs/log_writer.rb +43 -7
  186. data/lib/openc3/logs/packet_log_constants.rb +0 -0
  187. data/lib/openc3/logs/packet_log_reader.rb +23 -2
  188. data/lib/openc3/logs/packet_log_writer.rb +6 -2
  189. data/lib/openc3/logs/stream_log.rb +1 -1
  190. data/lib/openc3/logs/stream_log_pair.rb +0 -0
  191. data/lib/openc3/logs/text_log_writer.rb +0 -0
  192. data/lib/openc3/logs.rb +0 -0
  193. data/lib/openc3/microservices/cleanup_microservice.rb +0 -0
  194. data/lib/openc3/microservices/decom_common.rb +0 -0
  195. data/lib/openc3/microservices/decom_microservice.rb +0 -0
  196. data/lib/openc3/microservices/interface_decom_common.rb +2 -1
  197. data/lib/openc3/microservices/interface_microservice.rb +73 -26
  198. data/lib/openc3/microservices/log_microservice.rb +0 -0
  199. data/lib/openc3/microservices/microservice.rb +3 -3
  200. data/lib/openc3/microservices/multi_microservice.rb +1 -1
  201. data/lib/openc3/microservices/periodic_microservice.rb +2 -2
  202. data/lib/openc3/microservices/plugin_microservice.rb +0 -0
  203. data/lib/openc3/microservices/queue_microservice.rb +0 -0
  204. data/lib/openc3/microservices/router_microservice.rb +0 -0
  205. data/lib/openc3/microservices/scope_cleanup_microservice.rb +0 -0
  206. data/lib/openc3/microservices/text_log_microservice.rb +0 -0
  207. data/lib/openc3/migrations/20220420190000_log_stuff.rb +0 -0
  208. data/lib/openc3/migrations/20221202214600_add_target_names.rb +0 -0
  209. data/lib/openc3/migrations/20221210174900_convert_to_multi.rb +0 -0
  210. data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +0 -0
  211. data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +0 -0
  212. data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +0 -0
  213. data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +0 -0
  214. data/lib/openc3/migrations/20250108060000_news_feed.rb +0 -0
  215. data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +0 -0
  216. data/lib/openc3/migrations/20260203000000_remove_store_id.rb +0 -0
  217. data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +0 -0
  218. data/lib/openc3/migrations/20260701000000_updated_at_to_int.rb +0 -0
  219. data/lib/openc3/migrations/20260704000000_default_bridge.rb +38 -0
  220. data/lib/openc3/migrations/20260731000000_system_health_json.rb +52 -0
  221. data/lib/openc3/models/activity_model.rb +0 -0
  222. data/lib/openc3/models/auth_model.rb +35 -7
  223. data/lib/openc3/models/bridge_model.rb +133 -0
  224. data/lib/openc3/models/config_keyword_model.rb +63 -0
  225. data/lib/openc3/models/cvt_model.rb +5 -5
  226. data/lib/openc3/models/db_sharded_model.rb +0 -0
  227. data/lib/openc3/models/environment_model.rb +0 -0
  228. data/lib/openc3/models/gem_model.rb +13 -10
  229. data/lib/openc3/models/host_interface_microservice_model.rb +114 -0
  230. data/lib/openc3/models/info_model.rb +0 -0
  231. data/lib/openc3/models/interface_model.rb +179 -20
  232. data/lib/openc3/models/interface_status_model.rb +0 -0
  233. data/lib/openc3/models/metadata_model.rb +0 -0
  234. data/lib/openc3/models/metric_model.rb +0 -0
  235. data/lib/openc3/models/microservice_model.rb +26 -18
  236. data/lib/openc3/models/microservice_status_model.rb +0 -0
  237. data/lib/openc3/models/migration_model.rb +0 -0
  238. data/lib/openc3/models/model.rb +0 -0
  239. data/lib/openc3/models/news_model.rb +0 -0
  240. data/lib/openc3/models/note_model.rb +0 -0
  241. data/lib/openc3/models/offline_access_model.rb +0 -0
  242. data/lib/openc3/models/ping_model.rb +0 -0
  243. data/lib/openc3/models/plugin_model.rb +211 -50
  244. data/lib/openc3/models/plugin_store_model.rb +0 -0
  245. data/lib/openc3/models/process_status_model.rb +0 -0
  246. data/lib/openc3/models/python_package_model.rb +211 -15
  247. data/lib/openc3/models/queue_model.rb +0 -0
  248. data/lib/openc3/models/reaction_model.rb +0 -0
  249. data/lib/openc3/models/reingest_job_model.rb +0 -0
  250. data/lib/openc3/models/router_model.rb +0 -0
  251. data/lib/openc3/models/router_status_model.rb +0 -0
  252. data/lib/openc3/models/scope_model.rb +85 -56
  253. data/lib/openc3/models/script_engine_model.rb +0 -0
  254. data/lib/openc3/models/script_status_model.rb +0 -0
  255. data/lib/openc3/models/secret_model.rb +0 -0
  256. data/lib/openc3/models/setting_model.rb +546 -3
  257. data/lib/openc3/models/sorted_model.rb +0 -0
  258. data/lib/openc3/models/stash_model.rb +0 -0
  259. data/lib/openc3/models/target_model.rb +210 -31
  260. data/lib/openc3/models/timeline_model.rb +0 -0
  261. data/lib/openc3/models/tool_config_model.rb +0 -0
  262. data/lib/openc3/models/tool_model.rb +34 -20
  263. data/lib/openc3/models/trigger_group_model.rb +0 -0
  264. data/lib/openc3/models/trigger_model.rb +20 -0
  265. data/lib/openc3/models/widget_model.rb +0 -0
  266. data/lib/openc3/operators/microservice_operator.rb +79 -8
  267. data/lib/openc3/operators/operator.rb +4 -4
  268. data/lib/openc3/packets/binary_accessor.rb +0 -0
  269. data/lib/openc3/packets/command_validator.rb +0 -0
  270. data/lib/openc3/packets/commands.rb +4 -4
  271. data/lib/openc3/packets/json_packet.rb +0 -0
  272. data/lib/openc3/packets/limits.rb +15 -7
  273. data/lib/openc3/packets/limits_response.rb +0 -0
  274. data/lib/openc3/packets/packet.rb +5 -1
  275. data/lib/openc3/packets/packet_config.rb +0 -0
  276. data/lib/openc3/packets/packet_item.rb +0 -0
  277. data/lib/openc3/packets/packet_item_limits.rb +0 -0
  278. data/lib/openc3/packets/parsers/format_string_parser.rb +0 -0
  279. data/lib/openc3/packets/parsers/limits_parser.rb +0 -0
  280. data/lib/openc3/packets/parsers/limits_response_parser.rb +0 -0
  281. data/lib/openc3/packets/parsers/packet_item_parser.rb +0 -0
  282. data/lib/openc3/packets/parsers/packet_parser.rb +0 -0
  283. data/lib/openc3/packets/parsers/processor_parser.rb +0 -0
  284. data/lib/openc3/packets/parsers/state_parser.rb +1 -1
  285. data/lib/openc3/packets/parsers/xtce_converter.rb +183 -103
  286. data/lib/openc3/packets/parsers/xtce_parser.rb +71 -23
  287. data/lib/openc3/packets/structure.rb +9 -3
  288. data/lib/openc3/packets/structure_item.rb +0 -0
  289. data/lib/openc3/packets/telemetry.rb +3 -3
  290. data/lib/openc3/processors/processor.rb +2 -0
  291. data/lib/openc3/processors/statistics_processor.rb +0 -0
  292. data/lib/openc3/processors/watermark_processor.rb +0 -0
  293. data/lib/openc3/processors.rb +0 -0
  294. data/lib/openc3/script/api_shared.rb +0 -0
  295. data/lib/openc3/script/autonomic.rb +12 -12
  296. data/lib/openc3/script/calendar.rb +0 -0
  297. data/lib/openc3/script/commands.rb +1 -1
  298. data/lib/openc3/script/critical_cmd.rb +0 -0
  299. data/lib/openc3/script/exceptions.rb +0 -0
  300. data/lib/openc3/script/extract.rb +20 -25
  301. data/lib/openc3/script/limits.rb +0 -0
  302. data/lib/openc3/script/metadata.rb +0 -0
  303. data/lib/openc3/script/packages.rb +0 -0
  304. data/lib/openc3/script/plugins.rb +0 -0
  305. data/lib/openc3/script/queue.rb +0 -0
  306. data/lib/openc3/script/screen.rb +0 -0
  307. data/lib/openc3/script/script.rb +2 -2
  308. data/lib/openc3/script/script_runner.rb +0 -0
  309. data/lib/openc3/script/storage.rb +4 -4
  310. data/lib/openc3/script/suite.rb +0 -0
  311. data/lib/openc3/script/suite_results.rb +0 -0
  312. data/lib/openc3/script/suite_runner.rb +26 -0
  313. data/lib/openc3/script/tables.rb +0 -0
  314. data/lib/openc3/script/telemetry.rb +9 -3
  315. data/lib/openc3/script/web_socket_api.rb +247 -134
  316. data/lib/openc3/script.rb +0 -0
  317. data/lib/openc3/script_engines/script_engine.rb +0 -0
  318. data/lib/openc3/streams/mqtt_stream.rb +0 -0
  319. data/lib/openc3/streams/serial_stream.rb +0 -0
  320. data/lib/openc3/streams/stream.rb +0 -0
  321. data/lib/openc3/streams/tcpip_client_stream.rb +0 -0
  322. data/lib/openc3/streams/tcpip_socket_stream.rb +0 -0
  323. data/lib/openc3/streams/web_socket_client_stream.rb +0 -0
  324. data/lib/openc3/subpacketizers/subpacketizer.rb +0 -0
  325. data/lib/openc3/system/system.rb +0 -0
  326. data/lib/openc3/system/target.rb +0 -0
  327. data/lib/openc3/system.rb +0 -0
  328. data/lib/openc3/tools/cmd_tlm_server/api.rb +0 -0
  329. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +7 -0
  330. data/lib/openc3/tools/table_manager/table.rb +0 -0
  331. data/lib/openc3/tools/table_manager/table_config.rb +0 -0
  332. data/lib/openc3/tools/table_manager/table_item.rb +0 -0
  333. data/lib/openc3/tools/table_manager/table_item_parser.rb +0 -0
  334. data/lib/openc3/tools/table_manager/table_manager_core.rb +0 -0
  335. data/lib/openc3/tools/table_manager/table_parser.rb +0 -0
  336. data/lib/openc3/tools/test_runner/test.rb +0 -0
  337. data/lib/openc3/top_level.rb +1 -1
  338. data/lib/openc3/topics/autonomic_topic.rb +0 -0
  339. data/lib/openc3/topics/calendar_topic.rb +0 -0
  340. data/lib/openc3/topics/command_decom_topic.rb +16 -1
  341. data/lib/openc3/topics/command_topic.rb +0 -0
  342. data/lib/openc3/topics/config_topic.rb +0 -0
  343. data/lib/openc3/topics/decom_interface_topic.rb +2 -1
  344. data/lib/openc3/topics/interface_topic.rb +8 -2
  345. data/lib/openc3/topics/limits_event_topic.rb +1 -1
  346. data/lib/openc3/topics/notebook_topic.rb +0 -0
  347. data/lib/openc3/topics/queue_topic.rb +0 -0
  348. data/lib/openc3/topics/router_topic.rb +6 -1
  349. data/lib/openc3/topics/system_events_topic.rb +0 -0
  350. data/lib/openc3/topics/telemetry_decom_topic.rb +0 -0
  351. data/lib/openc3/topics/telemetry_topic.rb +0 -0
  352. data/lib/openc3/topics/timeline_topic.rb +0 -0
  353. data/lib/openc3/topics/topic.rb +0 -0
  354. data/lib/openc3/utilities/authentication.rb +4 -4
  355. data/lib/openc3/utilities/authorization.rb +0 -0
  356. data/lib/openc3/utilities/aws_bucket.rb +12 -4
  357. data/lib/openc3/utilities/bucket.rb +1 -1
  358. data/lib/openc3/utilities/bucket_file_cache.rb +55 -22
  359. data/lib/openc3/utilities/bucket_require.rb +0 -0
  360. data/lib/openc3/utilities/bucket_utilities.rb +3 -4
  361. data/lib/openc3/utilities/cli_generator.rb +0 -0
  362. data/lib/openc3/utilities/cmd_log.rb +0 -0
  363. data/lib/openc3/utilities/config_overlay.rb +75 -0
  364. data/lib/openc3/utilities/cosmos_rails_formatter.rb +0 -0
  365. data/lib/openc3/utilities/crc.rb +59 -32
  366. data/lib/openc3/utilities/csv.rb +5 -5
  367. data/lib/openc3/utilities/ctrf.rb +0 -0
  368. data/lib/openc3/utilities/env_helper.rb +0 -0
  369. data/lib/openc3/utilities/local_bucket.rb +0 -0
  370. data/lib/openc3/utilities/local_mode.rb +36 -7
  371. data/lib/openc3/utilities/logger.rb +30 -8
  372. data/lib/openc3/utilities/message_log.rb +0 -0
  373. data/lib/openc3/utilities/metric.rb +0 -0
  374. data/lib/openc3/utilities/migration.rb +0 -0
  375. data/lib/openc3/utilities/open_telemetry.rb +0 -0
  376. data/lib/openc3/utilities/process_manager.rb +0 -0
  377. data/lib/openc3/utilities/pypi_url.rb +0 -0
  378. data/lib/openc3/utilities/python_proxy.rb +0 -0
  379. data/lib/openc3/utilities/python_venv.rb +135 -0
  380. data/lib/openc3/utilities/quaternion.rb +0 -0
  381. data/lib/openc3/utilities/questdb_client.rb +0 -0
  382. data/lib/openc3/utilities/redis_secrets.rb +0 -0
  383. data/lib/openc3/utilities/reingest_job.rb +0 -0
  384. data/lib/openc3/utilities/ruby_lex_utils.rb +5 -1
  385. data/lib/openc3/utilities/rubygems_url.rb +39 -0
  386. data/lib/openc3/utilities/running_script.rb +119 -95
  387. data/lib/openc3/utilities/s3_autoload.rb +5 -5
  388. data/lib/openc3/utilities/script.rb +52 -12
  389. data/lib/openc3/utilities/secrets.rb +48 -3
  390. data/lib/openc3/utilities/simulated_target.rb +0 -0
  391. data/lib/openc3/utilities/sleeper.rb +0 -0
  392. data/lib/openc3/utilities/store.rb +0 -0
  393. data/lib/openc3/utilities/store_autoload.rb +2 -2
  394. data/lib/openc3/utilities/store_queued.rb +0 -0
  395. data/lib/openc3/utilities/target_file.rb +18 -1
  396. data/lib/openc3/utilities/thread_manager.rb +0 -0
  397. data/lib/openc3/utilities/throttle.rb +0 -0
  398. data/lib/openc3/utilities/zip.rb +0 -0
  399. data/lib/openc3/utilities.rb +0 -0
  400. data/lib/openc3/version.rb +6 -6
  401. data/lib/openc3/win32/excel.rb +0 -0
  402. data/lib/openc3/win32/win32.rb +0 -0
  403. data/lib/openc3/win32/win32_main.rb +0 -0
  404. data/lib/openc3.rb +2 -2
  405. data/tasks/gemfile_stats.rake +0 -0
  406. data/tasks/spec.rake +0 -0
  407. data/templates/command_validator/command_validator.py +0 -0
  408. data/templates/command_validator/command_validator.rb +0 -0
  409. data/templates/conversion/conversion.py +0 -0
  410. data/templates/conversion/conversion.rb +0 -0
  411. data/templates/limits_response/response.py +0 -0
  412. data/templates/limits_response/response.rb +0 -0
  413. data/templates/microservice/microservices/TEMPLATE/microservice.py +0 -0
  414. data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -0
  415. data/templates/plugin/.gitignore +0 -0
  416. data/templates/plugin/LICENSE.md +0 -0
  417. data/templates/plugin/README.md +0 -0
  418. data/templates/plugin/Rakefile +0 -0
  419. data/templates/plugin/plugin.gemspec +1 -1
  420. data/templates/plugin/plugin.txt +0 -0
  421. data/templates/processor/processor.py +1 -1
  422. data/templates/processor/processor.rb +0 -0
  423. data/templates/target/targets/TARGET/cmd_tlm/cmd.txt +0 -0
  424. data/templates/target/targets/TARGET/cmd_tlm/tlm.txt +0 -0
  425. data/templates/target/targets/TARGET/lib/target.py +0 -0
  426. data/templates/target/targets/TARGET/lib/target.rb +0 -0
  427. data/templates/target/targets/TARGET/procedures/procedure.py +0 -0
  428. data/templates/target/targets/TARGET/procedures/procedure.rb +0 -0
  429. data/templates/target/targets/TARGET/public/README.txt +0 -0
  430. data/templates/target/targets/TARGET/screens/status.txt +0 -0
  431. data/templates/target/targets/TARGET/target.txt +0 -0
  432. data/templates/tool_angular/.editorconfig +0 -0
  433. data/templates/tool_angular/.gitignore +0 -0
  434. data/templates/tool_angular/.vscode/extensions.json +0 -0
  435. data/templates/tool_angular/.vscode/launch.json +0 -0
  436. data/templates/tool_angular/.vscode/tasks.json +0 -0
  437. data/templates/tool_angular/angular.json +0 -0
  438. data/templates/tool_angular/extra-webpack.config.js +0 -0
  439. data/templates/tool_angular/package.json +2 -2
  440. data/templates/tool_angular/src/app/app-routing.module.ts +0 -0
  441. data/templates/tool_angular/src/app/app.component.html +0 -0
  442. data/templates/tool_angular/src/app/app.component.scss +0 -0
  443. data/templates/tool_angular/src/app/app.component.spec.ts +0 -0
  444. data/templates/tool_angular/src/app/app.component.ts +0 -0
  445. data/templates/tool_angular/src/app/app.module.ts +0 -0
  446. data/templates/tool_angular/src/app/custom-overlay-container.ts +0 -0
  447. data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +0 -0
  448. data/templates/tool_angular/src/app/openc3-api.d.ts +0 -0
  449. data/templates/tool_angular/src/assets/.gitkeep +0 -0
  450. data/templates/tool_angular/src/environments/environment.prod.ts +0 -0
  451. data/templates/tool_angular/src/environments/environment.ts +0 -0
  452. data/templates/tool_angular/src/favicon.ico +0 -0
  453. data/templates/tool_angular/src/index.html +0 -0
  454. data/templates/tool_angular/src/main.single-spa.ts +0 -0
  455. data/templates/tool_angular/src/single-spa/asset-url.ts +0 -0
  456. data/templates/tool_angular/src/single-spa/single-spa-props.ts +0 -0
  457. data/templates/tool_angular/src/styles.scss +0 -0
  458. data/templates/tool_angular/tsconfig.app.json +0 -0
  459. data/templates/tool_angular/tsconfig.json +0 -0
  460. data/templates/tool_angular/tsconfig.spec.json +0 -0
  461. data/templates/tool_react/.eslintrc +0 -0
  462. data/templates/tool_react/.gitignore +0 -0
  463. data/templates/tool_react/.prettierignore +0 -0
  464. data/templates/tool_react/babel.config.json +0 -0
  465. data/templates/tool_react/jest.config.js +0 -0
  466. data/templates/tool_react/package.json +1 -1
  467. data/templates/tool_react/src/openc3-tool_name.js +0 -0
  468. data/templates/tool_react/src/root.component.js +0 -0
  469. data/templates/tool_react/src/root.component.test.js +0 -0
  470. data/templates/tool_react/webpack.config.js +0 -0
  471. data/templates/tool_svelte/.gitignore +0 -0
  472. data/templates/tool_svelte/.prettierignore +0 -0
  473. data/templates/tool_svelte/.prettierrc.js +0 -0
  474. data/templates/tool_svelte/babel.config.js +0 -0
  475. data/templates/tool_svelte/build/smui.css +0 -0
  476. data/templates/tool_svelte/jest.config.js +0 -0
  477. data/templates/tool_svelte/package.json +1 -1
  478. data/templates/tool_svelte/rollup.config.js +0 -0
  479. data/templates/tool_svelte/src/App.svelte +0 -0
  480. data/templates/tool_svelte/src/App.test.js +0 -0
  481. data/templates/tool_svelte/src/theme/_smui-theme.scss +0 -0
  482. data/templates/tool_svelte/src/tool_name.js +0 -0
  483. data/templates/tool_vue/.env.standalone +0 -0
  484. data/templates/tool_vue/.gitignore +0 -0
  485. data/templates/tool_vue/.prettierrc.cjs +0 -0
  486. data/templates/tool_vue/eslint.config.mjs +0 -0
  487. data/templates/tool_vue/jsconfig.json +0 -0
  488. data/templates/tool_vue/package.json +3 -3
  489. data/templates/tool_vue/src/App.vue +0 -0
  490. data/templates/tool_vue/src/main.js +0 -0
  491. data/templates/tool_vue/src/router.js +0 -0
  492. data/templates/tool_vue/src/tools/tool_name/tool_name.vue +0 -0
  493. data/templates/tool_vue/vite.config.js +1 -1
  494. data/templates/widget/.prettierrc.cjs +0 -0
  495. data/templates/widget/LICENSE.md +0 -0
  496. data/templates/widget/Rakefile +0 -0
  497. data/templates/widget/package.json +2 -2
  498. data/templates/widget/src/Widget.vue +0 -0
  499. data/templates/widget/vite.config.js +0 -0
  500. metadata +40 -11
  501. data/templates/tool_vue/.nycrc +0 -3
  502. data/templates/widget/.nycrc +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13ecd5ed69a40943e0ceb4732af0922106d73ba3e28c7e10521e3cbcbb2728c9
4
- data.tar.gz: e8a55a75e964de92cdc8fa9a27091d472437004a0775a05c894d4a16d5232677
3
+ metadata.gz: 3d94ef0547084256ba519d150e9e7637fe2623ad68703fb56ff43579ceb1119b
4
+ data.tar.gz: bb907222d40154d622e73fb8732ff2715186183f5ce097f58832839ea3621fb3
5
5
  SHA512:
6
- metadata.gz: 77c7ed5bcae0862bf8d7ccdeefbc79cdc814b04501831e5de5a2b7b1d685420f731da2bb230435a1d091697156ab1d58a40cf793869da48e191b7c87ccbffea9
7
- data.tar.gz: 90571e3012ae117610314df3d32d67d77a843f2de8edb2c9b51bab3335cf0618e7301a9ba0c55616acad6a2d0ca1b4634924531f657bd438c0fd490aeca6a327
6
+ metadata.gz: d59f2a554a6fd751533736e12088e85958e9fe8569ccc2ffde017e68c00626b39ddd7f08334e9e9f83fa47a599b8c0a803c0da248b945a7dff3f8e41a41085cc
7
+ data.tar.gz: 54c6fc8f881f6ccfef18dd8e37ebbe99b078e199f95738b9f6da5d24183d279252a9ee563c2be338d4f4e2cf32bb0299b4761727b40ffb5f771e354ba3877538
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- source ENV['RUBYGEMS_URL'] || "https://rubygems.org"
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec :name => 'openc3'
6
6
 
data/Guardfile CHANGED
File without changes
data/LICENSE.md CHANGED
File without changes
data/README.md CHANGED
File without changes
data/Rakefile CHANGED
File without changes
data/bin/openc3cli CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  require 'openc3'
22
22
  require 'openc3/bridge/bridge'
23
+ require 'openc3/models/bridge_model'
23
24
  require 'openc3/models/gem_model'
24
25
  require 'openc3/models/migration_model'
25
26
  require 'openc3/models/plugin_model'
@@ -67,6 +68,7 @@ def print_usage
67
68
  puts " cli load /PATH/FILENAME.gem SCOPE plugin_hash.json # Loads a COSMOS plugin gem file"
68
69
  puts " OPTIONS: --variables lets you pass a path to a JSON file containing your plugin's variables"
69
70
  puts " cli list <SCOPE> # Lists installed plugins, SCOPE is DEFAULT if not given"
71
+ puts " cli unload PLUGIN_NAME [SCOPE] # Unload an installed COSMOS plugin"
70
72
  puts " cli generate TYPE OPTIONS # Generate various COSMOS entities"
71
73
  puts " OPTIONS: --ruby or --python is required to specify the language in the generated code unless OPENC3_LANGUAGE is set"
72
74
  puts " cli bridge CONFIG_FILENAME # Run COSMOS host bridge"
@@ -77,6 +79,8 @@ def print_usage
77
79
  puts " cli xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
78
80
  puts " cli cstol_converter # Converts CSTOL files (.prc) to COSMOS. Run with --help for more info."
79
81
  puts " cli setpassword # Set the initial password from OPENC3_API_PASSWORD env var"
82
+ puts " cli initsettings # Seed settings from OPENC3_SETTING_* env vars"
83
+ puts " cli migratetouv PLUGIN_NAME SCOPE # Migrate plugin to per-plugin UV virtual environment"
80
84
  puts ""
81
85
  end
82
86
 
@@ -102,6 +106,42 @@ def check_environment
102
106
  end
103
107
  end
104
108
 
109
+ # Report how an existing .xtce file fares against the XTCE 1.2 schema without failing
110
+ def xtce_report_validation(filename)
111
+ namespace = OpenC3::XtceConverter.xtce_namespace(filename)
112
+ if namespace != OpenC3::XtceConverter::XTCE_1_2_NAMESPACE
113
+ puts "#{File.basename(filename)} declares #{namespace ? namespace : 'no XTCE namespace'}, skipping XTCE 1.2 schema validation"
114
+ return
115
+ end
116
+ errors = OpenC3::XtceConverter.schema_errors(filename)
117
+ if errors.empty?
118
+ puts "#{File.basename(filename)} is valid XTCE 1.2"
119
+ else
120
+ $stderr.puts "WARNING: #{filename} is not valid XTCE 1.2:"
121
+ errors.each { |error| $stderr.puts " #{error}" }
122
+ end
123
+ end
124
+
125
+ # Validate every .xtce file written under output_dir. Returns false if any is invalid.
126
+ def xtce_validate_exported(output_dir)
127
+ files = Dir.glob(File.join(output_dir, "**", "*.xtce")).sort
128
+ if files.empty?
129
+ $stderr.puts "ERROR: no .xtce files were written to #{output_dir}"
130
+ return false
131
+ end
132
+ valid = true
133
+ files.each do |filename|
134
+ errors = OpenC3::XtceConverter.schema_errors(filename)
135
+ next if errors.empty?
136
+
137
+ valid = false
138
+ $stderr.puts "ERROR: #{filename} is not valid XTCE 1.2:"
139
+ errors.each { |error| $stderr.puts " #{error}" }
140
+ end
141
+ puts "Validated #{files.length} .xtce file(s) against the OMG XTCE 1.2 schema" if valid
142
+ valid
143
+ end
144
+
105
145
  def xtce_converter(args)
106
146
  options = {}
107
147
  option_parser = OptionParser.new do |opts|
@@ -122,14 +162,17 @@ def xtce_converter(args)
122
162
  opts.on("-p", "--plugin PLUGIN", "Export .xtce file(s) from the plugin") do |arg|
123
163
  options[:plugin] = arg
124
164
  end
125
- opts.on("-v", "--variables", "Optional variables file to pass to the plugin") do |arg|
165
+ opts.on("-v VARIABLES", "--variables VARIABLES", "Optional variables file to pass to the plugin") do |arg|
126
166
  options[:variables] = arg
127
167
  end
128
168
  opts.on("-r ROOT_TARGET", "--root_target ROOT_TARGET", "Optional flag to set which target is at the root of an XTCE document. If not specified, each target will be placed under a generic 'root' spacesystem") do |arg|
129
169
  options[:root_target_name] = arg
130
170
  end
131
- opts.on("-t TIME_ASSOCIATION_NAME", "--time_association_name TIME_ASSOCIATION_NAME", "Optional flag to set which target is at the root of an XTCE document. If not specified, each target will be placed under a generic 'root' spacesystem") do |arg|
132
- options[:time_association_name] = "PACKET_TIME"
171
+ opts.on("-t TIME_ASSOCIATION_NAME", "--time_association_name TIME_ASSOCIATION_NAME", "Optional telemetry item name to export as each packet's time, emitted as a TimeAssociation. If not specified, no TimeAssociation is written") do |arg|
172
+ options[:time_association_name] = arg
173
+ end
174
+ opts.on("--[no-]validate", "Validate .xtce files against the OMG XTCE 1.2 schema. On by default when exporting, where an invalid file fails the export. Off by default when importing, where it only reports since COSMOS also imports XTCE 1.0 / 1.1") do |arg|
175
+ options[:validate] = arg
133
176
  end
134
177
  end
135
178
 
@@ -149,6 +192,9 @@ def xtce_converter(args)
149
192
  OpenC3::Logger.level = OpenC3::Logger::DEBUG
150
193
 
151
194
  if options[:import] && options[:output]
195
+ # Reporting only. COSMOS imports XTCE 1.0 / 1.1 too, and those report errors against
196
+ # the 1.2 schema while importing perfectly well, so this never blocks an import.
197
+ xtce_report_validation(options[:import]) if options[:validate]
152
198
  packet_config = OpenC3::PacketConfig.new
153
199
  puts "Processing #{options[:import]}..."
154
200
  packet_config.process_file(options[:import], nil)
@@ -166,7 +212,14 @@ def xtce_converter(args)
166
212
  OpenC3::PluginModel.install_phase2(plugin_hash, scope: 'DEFAULT', validate_only: true,
167
213
  gem_file_path: options[:plugin])
168
214
  OpenC3::XtceConverter.combine_output_xtce(options[:output], options[:root_target_name])
169
- result = 0 # bash and Windows consider 0 success
215
+ # Validate what we just wrote unless told not to. An exporter bug that only shows
216
+ # up on a particular config otherwise produces a file that looks fine here and is
217
+ # rejected by whatever ground system it was written for.
218
+ if options[:validate] == false
219
+ result = 0
220
+ else
221
+ result = xtce_validate_exported(options[:output]) ? 0 : ERROR_CODE
222
+ end # bash and Windows consider 0 success
170
223
  rescue => e
171
224
  puts "Error: #{e.message}"
172
225
  puts e.backtrace
@@ -226,7 +279,7 @@ ensure
226
279
  exit(result)
227
280
  end
228
281
 
229
- def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_lines: nil, scope:, existing_plugin_name:, force: false)
282
+ def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_lines: nil, scope:, existing_plugin_name:, force: false, username: nil, version_history_files: nil)
230
283
  new_gem = File.basename(plugin_file_path)
231
284
  old_gem = existing_plugin_name.split("__")[0]
232
285
  puts "Updating existing plugin: #{existing_plugin_name} with #{File.basename(plugin_file_path)}"
@@ -247,6 +300,10 @@ def update_plugin(plugin_file_path, plugin_name, variables: nil, plugin_txt_line
247
300
  plugin_model.destroy
248
301
 
249
302
  plugin_hash = OpenC3::PluginModel.install_phase1(plugin_file_path, existing_variables: variables, existing_plugin_txt_lines: plugin_txt_lines, process_existing: true, scope: scope)
303
+ # Carry Version History upgrade hints into the regenerated hash so
304
+ # install_phase2 can version modified files taken from the plugin.
305
+ plugin_hash['username'] = username if username
306
+ plugin_hash['version_history_files'] = version_history_files if version_history_files
250
307
  puts "Updating plugin: #{plugin_file_path}\n#{plugin_hash}"
251
308
  plugin_hash = OpenC3::PluginModel.install_phase2(plugin_hash, scope: scope)
252
309
  OpenC3::LocalMode.update_local_plugin(plugin_file_path, plugin_hash, old_plugin_name: plugin_name, scope: scope)
@@ -410,7 +467,8 @@ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil, force: false, v
410
467
  if existing_plugin_hash
411
468
  # Upgrade or Edit
412
469
  update_plugin(plugin_file_path, plugin_hash['name'], variables: plugin_hash['variables'], scope: scope,
413
- plugin_txt_lines: plugin_hash['plugin_txt_lines'], existing_plugin_name: existing_plugin_hash['name'], force: force)
470
+ plugin_txt_lines: plugin_hash['plugin_txt_lines'], existing_plugin_name: existing_plugin_hash['name'], force: force,
471
+ username: plugin_hash['username'], version_history_files: plugin_hash['version_history_files'])
414
472
  else
415
473
  # New Install
416
474
  puts "Loading new plugin: #{plugin_file_path}\n#{plugin_hash}"
@@ -447,6 +505,10 @@ def unload_plugin(plugin_name, scope:)
447
505
  # Remove the backing gem now that no PluginModel references it,
448
506
  # so it disappears from the admin Packages tab.
449
507
  OpenC3::PluginModel.cleanup_gem(plugin_name, scope: scope)
508
+ # Drop this plugin's Version History repo. Uninstall-only: the upgrade
509
+ # path (update_plugin) reuses the repo and never reaches here, so history
510
+ # survives version bumps. No-op in Core / when versioning is disabled.
511
+ OpenC3::TargetModel.destroy_script_versions(plugin_name, scope: scope)
450
512
  OpenC3::Logger.info("PluginModel destroyed: #{plugin_name}", scope: scope)
451
513
  rescue => e
452
514
  abort("Error uninstalling plugin: #{scope}: #{plugin_name}: #{e.formatted}")
@@ -1209,6 +1271,42 @@ if not ARGV[0].nil? # argument(s) given
1209
1271
  params = [] unless params
1210
1272
  run_bridge(filename, params)
1211
1273
 
1274
+ when 'bridgeenroll'
1275
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1276
+ puts "Usage: cli bridgeenroll BRIDGE_NAME APP_PUBLIC_KEY [SCOPE]"
1277
+ puts ""
1278
+ puts "Authorize an openc3-app control identity for a bridge (Iroh hub) and"
1279
+ puts "print that bridge's current connection ticket. Used by openc3-app to"
1280
+ puts "auto-enroll over the local Docker control plane: the bridge then only"
1281
+ puts "accepts api/* control connections from the given app identity."
1282
+ puts ""
1283
+ puts "Arguments:"
1284
+ puts " BRIDGE_NAME Name of the bridge (hub)"
1285
+ puts " APP_PUBLIC_KEY openc3-app's Iroh public key (EndpointId, hex)"
1286
+ puts " SCOPE Scope (optional, default: OPENC3_SCOPE or DEFAULT)"
1287
+ puts ""
1288
+ puts "On success the bridge ticket is printed alone on stdout."
1289
+ exit 0
1290
+ end
1291
+ bridge_name = ARGV[1].to_s.upcase
1292
+ app_public_key = ARGV[2]
1293
+ abort("APP_PUBLIC_KEY is required (see --help)") if app_public_key.nil? || app_public_key.empty?
1294
+ unless app_public_key.match?(/\A[0-9a-f]{64}\z/i)
1295
+ abort("APP_PUBLIC_KEY must be exactly 64 hexadecimal characters")
1296
+ end
1297
+ app_public_key = app_public_key.downcase
1298
+ scope = ARGV[3] || ENV['OPENC3_SCOPE'] || 'DEFAULT'
1299
+ model = OpenC3::BridgeModel.get_model(name: bridge_name, scope: scope)
1300
+ abort("Bridge '#{bridge_name}' not found in scope #{scope}. Is its bridge_microservice running?") unless model
1301
+ if model.ticket.nil? || model.ticket.empty?
1302
+ abort("Bridge '#{bridge_name}' has no ticket yet. Is its bridge_microservice running?")
1303
+ end
1304
+ old_app_public_key = model.app_public_key
1305
+ model.app_public_key = app_public_key
1306
+ model.update
1307
+ # Print ONLY the ticket so openc3-app can capture it from stdout.
1308
+ puts model.ticket
1309
+
1212
1310
  when 'bridgegem'
1213
1311
  if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1214
1312
  puts "Usage: cli bridgegem GEM_NAME [PARAMS...]"
@@ -1432,6 +1530,106 @@ if not ARGV[0].nil? # argument(s) given
1432
1530
  # Always ensure the scriptrunner policy is in place since it is required for script execution
1433
1531
  client.ensure_scriptrunner_policy(ENV['OPENC3_CONFIG_BUCKET'], ENV['OPENC3_LOGS_BUCKET'])
1434
1532
 
1533
+ when 'initsettings'
1534
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1535
+ puts "Usage: cli initsettings [--dry-run | --export]"
1536
+ puts ""
1537
+ puts "Seed COSMOS settings from the environment. A setting changed in the Admin"
1538
+ puts "Console is left alone, so those edits survive a restart."
1539
+ puts ""
1540
+ puts "Environment:"
1541
+ puts " OPENC3_SETTING_<NAME> One variable per setting, e.g."
1542
+ puts " OPENC3_SETTING_TIME_ZONE=UTC sets 'time_zone'"
1543
+ puts " OPENC3_SETTINGS_OVERWRITE true to overwrite existing settings on every"
1544
+ puts " run. false/unset leaves them alone"
1545
+ puts " OPENC3_SETTINGS_ALLOW_UNKNOWN true to allow setting names COSMOS doesn't"
1546
+ puts " recognize. Without it an unknown name is"
1547
+ puts " reported and skipped, so a typo can't"
1548
+ puts " silently do nothing"
1549
+ puts " OPENC3_SETTINGS_STRICT true to exit non-zero when a setting is"
1550
+ puts " rejected. Off by default"
1551
+ puts ""
1552
+ puts "These three accept true/false (1/0 also work)."
1553
+ puts ""
1554
+ puts "A setting that already exists is left alone because an operator may have"
1555
+ puts "edited it in the Admin Console. Settings written by a release before this"
1556
+ puts "command existed carry no record of having been seeded, so they all count as"
1557
+ puts "edited: on such an upgrade run one init with OPENC3_SETTINGS_OVERWRITE=true"
1558
+ puts "to adopt the environment values, then turn it back off."
1559
+ puts ""
1560
+ puts "An unrecognized name, an invalid value, or a malformed one of the variables"
1561
+ puts "above is reported on stdout and that one setting is skipped; init continues"
1562
+ puts "and COSMOS uses the default. Nothing here fails init unless"
1563
+ puts "OPENC3_SETTINGS_STRICT is set. Use --dry-run to check the same things before"
1564
+ puts "starting COSMOS, where a non-zero exit is what you want."
1565
+ puts ""
1566
+ puts "Settings that can be seeded:"
1567
+ OpenC3::SettingModel.describe_settings.each { |line| puts " #{line}" }
1568
+ puts ""
1569
+ puts "Boolean settings accept true/false (1/0 also work) and are stored as real"
1570
+ puts "booleans."
1571
+ puts "Every other setting is stored as the text given, including the settings"
1572
+ puts "whose text is JSON (astro, classification_banner, context_tag)."
1573
+ puts ""
1574
+ puts "JSON settings - shape of each blob:"
1575
+ OpenC3::SettingModel.describe_json_settings.each do |name, example|
1576
+ puts " #{name}"
1577
+ puts " #{example}"
1578
+ end
1579
+ puts ""
1580
+ puts "Rather than hand-writing one of those, configure it in Admin -> Settings"
1581
+ puts "and run 'cli initsettings --export' to print the current values as lines"
1582
+ puts "you can paste straight into compose.override.yaml."
1583
+ puts ""
1584
+ puts "Options:"
1585
+ puts " --dry-run Report what would be seeded and exit without writing."
1586
+ puts " Lists every problem rather than stopping at the first,"
1587
+ puts " and works before Redis is up so it can be run ahead of"
1588
+ puts " starting COSMOS. Exits non-zero if anything would fail,"
1589
+ puts " regardless of OPENC3_SETTINGS_STRICT"
1590
+ puts " --export Print the settings currently stored as compose"
1591
+ puts " 'environment:' lines, quoted so the JSON ones parse."
1592
+ puts " Configure in Admin -> Settings, then export and paste."
1593
+ puts " Reads Redis, so COSMOS must be running - unlike"
1594
+ puts " --dry-run, which works while it is down"
1595
+ puts " -h, --help Show this help message"
1596
+ exit 0
1597
+ end
1598
+ dry_run = ARGV[1] == '--dry-run'
1599
+ export = ARGV[1] == '--export'
1600
+ if ARGV[1] and !dry_run and !export
1601
+ abort "Unknown option #{ARGV[1]}. See 'cli initsettings --help'"
1602
+ end
1603
+ if export
1604
+ # --export reads the stored values, so it needs a reachable Redis. Say so
1605
+ # plainly - the raw connection error is something like
1606
+ # "Bad file descriptor (redis://openc3-redis:6379)", which doesn't hint
1607
+ # that the answer is to start COSMOS.
1608
+ unless OpenC3::SettingModel.redis_available?
1609
+ abort "Cannot reach Redis at #{ENV['OPENC3_REDIS_HOSTNAME']}:#{ENV['OPENC3_REDIS_PORT']}.\n" \
1610
+ "--export reads the settings currently stored, so COSMOS has to be running.\n" \
1611
+ "Start it with './openc3.sh run', or use --dry-run, which works while COSMOS is down."
1612
+ end
1613
+ begin
1614
+ lines = OpenC3::SettingModel.export_lines
1615
+ rescue => e
1616
+ abort "Error reading settings: #{e.message}"
1617
+ end
1618
+ if lines.empty?
1619
+ puts "# No settings are stored yet - configure them in Admin -> Settings first"
1620
+ else
1621
+ puts "# Paste under the openc3-cosmos-init service's \"environment:\" key in"
1622
+ puts "# compose.override.yaml, keeping this indentation."
1623
+ lines.each { |line| puts " #{line}" }
1624
+ end
1625
+ else
1626
+ begin
1627
+ OpenC3::SettingModel.apply_defaults(dry_run: dry_run)
1628
+ rescue => e
1629
+ abort "Error applying default settings: #{e.message}"
1630
+ end
1631
+ end
1632
+
1435
1633
  when 'runmigrations'
1436
1634
  if ARGV[1] == '--help' || ARGV[1] == '-h'
1437
1635
  puts "Usage: cli runmigrations"
@@ -1463,6 +1661,37 @@ if not ARGV[0].nil? # argument(s) given
1463
1661
  when 'migratepassword'
1464
1662
  migrate_password_hash()
1465
1663
 
1664
+ when 'migratetouv'
1665
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1666
+ puts "Usage: cli migratetouv PLUGIN_NAME [SCOPE]"
1667
+ puts ""
1668
+ puts "Migrate a plugin from the shared Python venv to a per-plugin UV virtual environment"
1669
+ puts ""
1670
+ puts "Arguments:"
1671
+ puts " PLUGIN_NAME Name of the plugin to migrate (required)"
1672
+ puts " SCOPE Scope of the plugin (optional, default: DEFAULT)"
1673
+ puts ""
1674
+ puts "Options:"
1675
+ puts " -h, --help Show this help message"
1676
+ exit(ARGV[1].nil? ? 1 : 0)
1677
+ end
1678
+ scope = ARGV[2] || 'DEFAULT'
1679
+ check_environment()
1680
+ begin
1681
+ plugin_model = OpenC3::PluginModel.get_model(name: ARGV[1], scope: scope)
1682
+ if plugin_model.nil?
1683
+ abort("Plugin '#{ARGV[1]}' not found in scope '#{scope}'")
1684
+ end
1685
+ if plugin_model.migrate_to_uv!(scope: scope)
1686
+ puts "Successfully migrated plugin '#{ARGV[1]}' to per-plugin UV venv"
1687
+ else
1688
+ puts "Migration failed for plugin '#{ARGV[1]}'. Check logs for details."
1689
+ exit 1
1690
+ end
1691
+ rescue => e
1692
+ abort("Error migrating plugin: #{e.formatted}")
1693
+ end
1694
+
1466
1695
  else # Unknown task
1467
1696
  print_usage()
1468
1697
  abort("Unknown task: #{ARGV[0]}")
data/bin/pipinstall CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/bin/sh
2
- uv venv "$PYTHONUSERBASE" --allow-existing
2
+ VENV="${PIPINSTALL_VENV:-$PYTHONUSERBASE}"
3
+ uv venv "$VENV" --allow-existing
3
4
  echo "uv pip install $@"
4
- uv pip install --python "$PYTHONUSERBASE" "$@"
5
+ uv pip install --python "$VENV" "$@"
5
6
  if [ $? -eq 0 ]; then
6
7
  echo "Command succeeded"
7
8
  exit 0
@@ -27,7 +28,7 @@ if [ -d "$LAST_ARG" ] && [ -f "$LAST_ARG/pyproject.toml" ]; then
27
28
  TMPFILE=$(mktemp)
28
29
  uv pip compile ${OPTS} "${LAST_ARG}/pyproject.toml" > "$TMPFILE"
29
30
  if [ $? -eq 0 ] && [ -s "$TMPFILE" ]; then
30
- uv pip install --python "$PYTHONUSERBASE" ${OPTS} -r "$TMPFILE"
31
+ uv pip install --python "$VENV" ${OPTS} -r "$TMPFILE"
31
32
  if [ $? -eq 0 ]; then
32
33
  echo "Dependencies installed successfully"
33
34
  rm -f "$TMPFILE"
@@ -38,7 +39,7 @@ if [ -d "$LAST_ARG" ] && [ -f "$LAST_ARG/pyproject.toml" ]; then
38
39
  fi
39
40
 
40
41
  echo "Warning: Install failed - retrying with --no-index"
41
- uv pip install --python "$PYTHONUSERBASE" --no-index "$@"
42
+ uv pip install --python "$VENV" --no-index "$@"
42
43
  if [ $? -ne 0 ]; then
43
44
  echo "ERROR: uv pip install failed"
44
45
  exit 1
data/bin/pipuninstall CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/bin/sh
2
+ # Uninstall a Python package from a venv. When PIPINSTALL_VENV is set (by
3
+ # PythonPackageModel.destroy for per-plugin venvs), uninstall from that venv.
4
+ # Otherwise fall back to the shared PYTHONUSERBASE.
5
+ VENV="${PIPINSTALL_VENV:-$PYTHONUSERBASE}"
2
6
  echo "uv pip uninstall $@"
3
- uv pip uninstall --python "$PYTHONUSERBASE" "$@"
7
+ uv pip uninstall --python "$VENV" "$@"
4
8
  if [ $? -eq 0 ]; then
5
9
  echo "Command succeeded"
6
10
  else
data/bin/uvinstall ADDED
@@ -0,0 +1,156 @@
1
+ #!/bin/sh
2
+ # Per-plugin UV virtual environment installer
3
+ # Usage: uvinstall <plugin_venv_name> <gem_path> [extra uv args...]
4
+ #
5
+ # Creates an isolated venv at /gems/plugin_venvs/<plugin_venv_name>/.venv
6
+ # and installs Python dependencies from the plugin's gem_path.
7
+ #
8
+ # Two installation paths:
9
+ # 1. If gem_path contains uv.lock: uses `uv sync --frozen` (reproducible)
10
+ # 2. Otherwise: falls back to `uv pip install` for requirements.txt / pyproject.toml
11
+ #
12
+ # Network safety: uv's own HTTP controls (connect timeout, read timeout,
13
+ # bounded retries) make a slow or unreachable index fail fast instead of
14
+ # hanging the plugin install (which stalls the whole deploy - the init hook
15
+ # never completes and helm's --wait times out). These are idle/connect
16
+ # timeouts, NOT a total-transfer cap, so a large but healthy download (e.g.
17
+ # torch over a slow link) is never killed mid-stream as long as bytes keep
18
+ # arriving. Both paths try OFFLINE first so a plugin whose wheels are already
19
+ # in the seeded UV cache installs deterministically without ever touching the
20
+ # network.
21
+
22
+ PLUGIN_VENV_NAME="$1"
23
+ GEM_PATH="$2"
24
+ shift 2
25
+ UV_ARGS="$@"
26
+
27
+ if [ -z "$PLUGIN_VENV_NAME" ] || [ -z "$GEM_PATH" ]; then
28
+ echo "Usage: uvinstall <plugin_venv_name> <gem_path> [extra uv args...]"
29
+ exit 1
30
+ fi
31
+
32
+ # Bound uv's network behavior with uv's own HTTP knobs. Unlike a blunt
33
+ # wall-clock cap, these fail fast on a dead/unreachable index or a stalled
34
+ # connection WITHOUT killing a large but progressing download. All overridable.
35
+ # UV_HTTP_CONNECT_TIMEOUT - give up connecting to an unreachable index (s)
36
+ # UV_HTTP_TIMEOUT - give up when a connection stalls mid-read (s)
37
+ # UV_HTTP_RETRIES - bounded retries for transient failures
38
+ # The values below match uv's own defaults; they are set explicitly so plugin
39
+ # installs keep this behavior even if a future uv release changes its defaults,
40
+ # and so an operator has a documented place to raise them for a slow index.
41
+ export UV_HTTP_CONNECT_TIMEOUT="${UV_HTTP_CONNECT_TIMEOUT:-10}"
42
+ export UV_HTTP_TIMEOUT="${UV_HTTP_TIMEOUT:-30}"
43
+ export UV_HTTP_RETRIES="${UV_HTTP_RETRIES:-3}"
44
+
45
+ # Run a uv command offline first (cache-only: instant, cannot hang, works in
46
+ # air-gapped clusters) and only retry online on a cache miss. Both paths below
47
+ # use this so a plugin whose wheels are already in the seeded UV cache never
48
+ # touches the network.
49
+ uv_offline_then_online() {
50
+ if uv "$@" --offline; then
51
+ return 0
52
+ fi
53
+ # Expected for any plugin whose wheels aren't in the seeded cache (a new
54
+ # third-party plugin, or a pin that differs from the one baked in), so this
55
+ # is informational, not an error - the online attempt below is the real one.
56
+ echo "Offline uv cache miss; retrying online"
57
+ uv "$@"
58
+ }
59
+
60
+ VENV_BASE="/gems/plugin_venvs/${PLUGIN_VENV_NAME}"
61
+ VENV_DIR="${VENV_BASE}/.venv"
62
+
63
+ echo "Creating per-plugin venv for '${PLUGIN_VENV_NAME}' at ${VENV_DIR}"
64
+ mkdir -p "${VENV_BASE}"
65
+
66
+ # Path 1: uv.lock present - use `uv sync --frozen` for reproducible installs
67
+ if [ -f "${GEM_PATH}/uv.lock" ] && [ -f "${GEM_PATH}/pyproject.toml" ]; then
68
+ echo "Found uv.lock - using uv sync --frozen for reproducible install"
69
+
70
+ # Copy pyproject.toml and uv.lock into the venv base directory
71
+ cp "${GEM_PATH}/pyproject.toml" "${VENV_BASE}/pyproject.toml"
72
+ cp "${GEM_PATH}/uv.lock" "${VENV_BASE}/uv.lock"
73
+
74
+ # Create venv and sync dependencies
75
+ cd "${VENV_BASE}"
76
+ uv venv "${VENV_DIR}" --allow-existing
77
+
78
+ # Offline sync first, online only on a cache miss (bounded by UV_HTTP_*).
79
+ # --inexact keeps sync additive: without it sync makes the venv match the
80
+ # lock exactly and uninstalls anything else, including packages an admin
81
+ # uploaded into this plugin venv via PythonPackageModel.install (which uses
82
+ # the additive `pipinstall`).
83
+ uv_offline_then_online sync --frozen --inexact --no-dev --no-install-project ${UV_ARGS}
84
+ RESULT=$?
85
+
86
+ if [ $RESULT -eq 0 ]; then
87
+ echo "uv sync --frozen succeeded"
88
+ touch "${VENV_BASE}/.uv_managed"
89
+ exit 0
90
+ fi
91
+
92
+ echo "Warning: uv sync --frozen failed (exit code ${RESULT}), falling back to uv pip install"
93
+ fi
94
+
95
+ # Path 2: Fallback - use uv pip install for requirements.txt or pyproject.toml
96
+ # Every install here is also offline-first (same reasoning as path 1), so an
97
+ # unlocked plugin whose wheels happen to be cached installs without network too.
98
+ uv venv "${VENV_DIR}" --allow-existing
99
+
100
+ if [ -f "${GEM_PATH}/requirements.txt" ]; then
101
+ echo "Installing from requirements.txt via uv pip install"
102
+ uv_offline_then_online pip install --python "${VENV_DIR}" ${UV_ARGS} -r "${GEM_PATH}/requirements.txt"
103
+ RESULT=$?
104
+ elif [ -f "${GEM_PATH}/pyproject.toml" ]; then
105
+ echo "Installing from pyproject.toml via uv pip install"
106
+ # --python: The Python interpreter into which packages should be installed.
107
+ # --project: Discover a project (i.e. pyproject.toml) in the given directory.
108
+ # -r: Install the packages listed in the given files.
109
+ uv_offline_then_online pip install --python "${VENV_DIR}" --project "${GEM_PATH}" ${UV_ARGS} -r "${GEM_PATH}/pyproject.toml"
110
+ RESULT=$?
111
+
112
+ # `uv pip install <path>` builds the plugin as a package before installing
113
+ # its dependencies, which fails for a pyproject.toml that only declares
114
+ # dependencies and isn't a buildable distribution (no [build-system], a
115
+ # missing/empty source layout, or a build backend that can't run offline).
116
+ # Fall back to installing the declared dependencies without building. The
117
+ # compile step only resolves declared deps into a pinned requirements file;
118
+ # the install that follows it is the one that fetches, so it gets the same
119
+ # offline-then-online treatment. Each compile attempt re-truncates TMPFILE
120
+ # so a partial offline write can never be mixed into the online result.
121
+ if [ $RESULT -ne 0 ]; then
122
+ echo "Warning: Failed to build Python package, attempting to install declared dependencies from pyproject.toml"
123
+ TMPFILE=$(mktemp)
124
+ uv pip compile --offline ${UV_ARGS} "${GEM_PATH}/pyproject.toml" > "$TMPFILE"
125
+ COMPILED=$?
126
+ if [ $COMPILED -ne 0 ] || [ ! -s "$TMPFILE" ]; then
127
+ echo "Offline uv pip compile missed the cache; retrying online"
128
+ uv pip compile ${UV_ARGS} "${GEM_PATH}/pyproject.toml" > "$TMPFILE"
129
+ COMPILED=$?
130
+ fi
131
+ # Both the exit status AND a non-empty file are required: uv writes its
132
+ # "autogenerated by uv" header before resolution runs, so a compile that
133
+ # fails partway still leaves a non-empty file. Installing from that would
134
+ # produce a venv missing dependencies and report success.
135
+ if [ $COMPILED -eq 0 ] && [ -s "$TMPFILE" ]; then
136
+ uv_offline_then_online pip install --python "${VENV_DIR}" ${UV_ARGS} -r "$TMPFILE"
137
+ RESULT=$?
138
+ fi
139
+ rm -f "$TMPFILE"
140
+ fi
141
+ else
142
+ echo "ERROR: No requirements.txt, pyproject.toml, or uv.lock found in ${GEM_PATH}"
143
+ exit 1
144
+ fi
145
+
146
+ if [ $RESULT -eq 0 ]; then
147
+ echo "Python packages installed successfully"
148
+ touch "${VENV_BASE}/.uv_managed"
149
+ exit 0
150
+ fi
151
+
152
+ # No --no-index last resort here anymore: every attempt above already ran
153
+ # cache-only first via uv_offline_then_online, so a cache-only retry at this
154
+ # point would repeat an attempt that has already failed.
155
+ echo "ERROR: uvinstall failed for plugin ${PLUGIN_VENV_NAME}"
156
+ exit 1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -284,6 +284,8 @@ TEMPLATE_FILE:
284
284
  - name: Template File Path
285
285
  required: true
286
286
  description: The relative path to the template file. Filename should generally start with an underscore.
287
+ Absolute paths and paths containing '..' are not allowed. The file must be inside the directory
288
+ containing the definition file.
287
289
  values: .+
288
290
  since: 5.0.10
289
291
  RESPONSE:
File without changes
File without changes
File without changes