cosmos 3.1.1 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Manifest.txt +6 -0
- data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +1 -1
- data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/autohotkey/tools/autohotkey.rb +1 -1
- data/autohotkey/tools/cmd_tlm_server.ahk +1 -0
- data/autohotkey/tools/packet_viewer.ahk +45 -2
- data/data/crc.txt +20 -15
- data/demo/Rakefile +16 -0
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/demo/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/demo/procedures/example_test.rb +1 -1
- data/install/Rakefile +16 -0
- data/install/config/data/crc.txt +2 -2
- data/install/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/install/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +64 -57
- data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +0 -9
- data/lib/cosmos/gui/qt.rb +22 -18
- data/lib/cosmos/packet_logs/packet_log_writer.rb +6 -2
- data/lib/cosmos/script/script.rb +1 -1
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +0 -1
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +99 -784
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +189 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +176 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +144 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +240 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +90 -0
- data/lib/cosmos/tools/launcher/launcher_config.rb +142 -110
- data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
- data/lib/cosmos/tools/test_runner/test_runner.rb +3 -2
- data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +18 -2
- data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +4 -9
- data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +5 -5
- data/lib/cosmos/top_level.rb +1 -1
- data/lib/cosmos/version.rb +4 -4
- data/run_gui_tests.bat +33 -31
- data/spec/core_ext/time_spec.rb +51 -0
- data/spec/script/script_spec.rb +96 -0
- data/spec/tools/cmd_tlm_server/commanding_spec.rb +28 -0
- data/spec/tools/cmd_tlm_server/connections_spec.rb +88 -0
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +78 -25
- data/spec/tools/launcher/launcher_config_spec.rb +460 -0
- data/spec/top_level/top_level_spec.rb +1 -1
- metadata +8 -2
@@ -0,0 +1,240 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2014 Ball Aerospace & Technologies Corp.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
|
11
|
+
require 'cosmos'
|
12
|
+
require 'cosmos/gui/qt'
|
13
|
+
|
14
|
+
module Cosmos
|
15
|
+
|
16
|
+
# Implements the status tab in the Command and Telemetry Server GUI
|
17
|
+
class StatusTab
|
18
|
+
|
19
|
+
# Create the status tab and add it to the tab_widget
|
20
|
+
#
|
21
|
+
# @param tab_widget [Qt::TabWidget] The tab widget to add the tab to
|
22
|
+
def populate(tab_widget)
|
23
|
+
scroll = Qt::ScrollArea.new
|
24
|
+
widget = Qt::Widget.new
|
25
|
+
layout = Qt::VBoxLayout.new(widget)
|
26
|
+
|
27
|
+
populate_limits_status(layout)
|
28
|
+
populate_api_status(layout)
|
29
|
+
populate_system_status(layout)
|
30
|
+
populate_background_status(layout)
|
31
|
+
|
32
|
+
# Set the scroll area widget last now that all the items have been layed out
|
33
|
+
scroll.setWidget(widget)
|
34
|
+
tab_widget.addTab(scroll, "Status")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Update the status tab in the GUI
|
38
|
+
#
|
39
|
+
# @param previous_request_count [Integer] The previous number of
|
40
|
+
def update(previous_request_count)
|
41
|
+
update_limits_set
|
42
|
+
update_api_status(previous_request_count)
|
43
|
+
update_system_status
|
44
|
+
update_background_task_status
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def populate_limits_status(layout)
|
50
|
+
limits = Qt::GroupBox.new(Qt::Object.tr("Limits Status"))
|
51
|
+
limits_layout = Qt::FormLayout.new(limits)
|
52
|
+
current_limits_set = System.limits_set.to_s
|
53
|
+
|
54
|
+
known_limits_sets = System.limits.sets
|
55
|
+
known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
|
56
|
+
current_index = known_limits_sets.index(current_limits_set.to_s)
|
57
|
+
|
58
|
+
@limits_set_combo = Qt::ComboBox.new
|
59
|
+
limits_layout.addRow("Limits Set:", @limits_set_combo)
|
60
|
+
layout.addWidget(limits)
|
61
|
+
|
62
|
+
known_limits_sets.sort.each do |limits_set|
|
63
|
+
@limits_set_combo.addItem(limits_set.to_s)
|
64
|
+
end
|
65
|
+
@limits_set_combo.setMaxVisibleItems(6)
|
66
|
+
@limits_set_combo.setCurrentIndex(current_index)
|
67
|
+
# Only connect to the signal that is sent when the user chooses an item.
|
68
|
+
# If the limits set is changed programatically the code in
|
69
|
+
# handle_status_tab will pick up the change.
|
70
|
+
@limits_set_combo.connect(SIGNAL('activated(int)')) do
|
71
|
+
selected_limits_set = @limits_set_combo.currentText
|
72
|
+
if selected_limits_set
|
73
|
+
System.limits_set = selected_limits_set.intern if System.limits_set != selected_limits_set.intern
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def populate_api_status(layout)
|
79
|
+
api = Qt::GroupBox.new(Qt::Object.tr("API Status"))
|
80
|
+
api_layout = Qt::VBoxLayout.new(api)
|
81
|
+
@api_table = Qt::TableWidget.new()
|
82
|
+
@api_table.verticalHeader.hide()
|
83
|
+
@api_table.setRowCount(1)
|
84
|
+
@api_table.setColumnCount(6)
|
85
|
+
@api_table.setHorizontalHeaderLabels(["Port", "Num Clients", "Requests", "Requests/Sec", "Avg Request Time", "Estimated Utilization"])
|
86
|
+
|
87
|
+
@api_table.setItem(0, 0, Qt::TableWidgetItem.new(Qt::Object.tr(System.ports['CTS_API'].to_s)))
|
88
|
+
item0 = Qt::TableWidgetItem.new(Qt::Object.tr(CmdTlmServer.json_drb.num_clients.to_s))
|
89
|
+
item0.setTextAlignment(Qt::AlignCenter)
|
90
|
+
@api_table.setItem(0, 1, item0)
|
91
|
+
item = Qt::TableWidgetItem.new(Qt::Object.tr(CmdTlmServer.json_drb.request_count.to_s))
|
92
|
+
item.setTextAlignment(Qt::AlignCenter)
|
93
|
+
@api_table.setItem(0, 2, item)
|
94
|
+
item2 = Qt::TableWidgetItem.new("0.0")
|
95
|
+
item2.setTextAlignment(Qt::AlignCenter)
|
96
|
+
@api_table.setItem(0, 3, item2)
|
97
|
+
item3 = Qt::TableWidgetItem.new("0.0")
|
98
|
+
item3.setTextAlignment(Qt::AlignCenter)
|
99
|
+
@api_table.setItem(0, 4, item3)
|
100
|
+
item4 = Qt::TableWidgetItem.new("0.0")
|
101
|
+
item4.setTextAlignment(Qt::AlignCenter)
|
102
|
+
@api_table.setItem(0, 5, item4)
|
103
|
+
@api_table.displayFullSize
|
104
|
+
api_layout.addWidget(@api_table)
|
105
|
+
layout.addWidget(api)
|
106
|
+
end
|
107
|
+
|
108
|
+
def populate_system_status(layout)
|
109
|
+
system = Qt::GroupBox.new(Qt::Object.tr("System Status"))
|
110
|
+
system_layout = Qt::VBoxLayout.new(system)
|
111
|
+
@system_table = Qt::TableWidget.new()
|
112
|
+
@system_table.verticalHeader.hide()
|
113
|
+
@system_table.setRowCount(1)
|
114
|
+
@system_table.setColumnCount(4)
|
115
|
+
@system_table.setHorizontalHeaderLabels(["Threads", "Total Objs", "Free Objs", "Allocated Objs"])
|
116
|
+
|
117
|
+
item0 = Qt::TableWidgetItem.new("0")
|
118
|
+
item0.setTextAlignment(Qt::AlignCenter)
|
119
|
+
@system_table.setItem(0, 0, item0)
|
120
|
+
item1 = Qt::TableWidgetItem.new("0.0")
|
121
|
+
item1.setTextAlignment(Qt::AlignCenter)
|
122
|
+
@system_table.setItem(0, 1, item1)
|
123
|
+
item2 = Qt::TableWidgetItem.new("0.0")
|
124
|
+
item2.setTextAlignment(Qt::AlignCenter)
|
125
|
+
@system_table.setItem(0, 2, item2)
|
126
|
+
item3 = Qt::TableWidgetItem.new("0.0")
|
127
|
+
item3.setTextAlignment(Qt::AlignCenter)
|
128
|
+
@system_table.setItem(0, 3, item3)
|
129
|
+
@system_table.displayFullSize
|
130
|
+
system_layout.addWidget(@system_table)
|
131
|
+
layout.addWidget(system)
|
132
|
+
end
|
133
|
+
|
134
|
+
def populate_background_status(layout)
|
135
|
+
background_tasks_groupbox = Qt::GroupBox.new(Qt::Object.tr("Background Tasks"))
|
136
|
+
background_tasks_layout = Qt::VBoxLayout.new(background_tasks_groupbox)
|
137
|
+
@background_tasks_table = Qt::TableWidget.new()
|
138
|
+
@background_tasks_table.verticalHeader.hide()
|
139
|
+
@background_tasks_table.setRowCount(CmdTlmServer.background_tasks.all.length)
|
140
|
+
@background_tasks_table.setColumnCount(3)
|
141
|
+
@background_tasks_table.setHorizontalHeaderLabels(["Name", "State", "Status"])
|
142
|
+
|
143
|
+
background_tasks = CmdTlmServer.background_tasks.all
|
144
|
+
if background_tasks.length > 0
|
145
|
+
row = 0
|
146
|
+
background_tasks.each_with_index do |background_task, index|
|
147
|
+
background_task_name = background_task.name
|
148
|
+
background_task_name = "Background Task ##{index + 1}" unless background_task_name
|
149
|
+
background_task_name_widget = Qt::TableWidgetItem.new(background_task_name)
|
150
|
+
background_task_name_widget.setTextAlignment(Qt::AlignCenter)
|
151
|
+
@background_tasks_table.setItem(row, 0, background_task_name_widget)
|
152
|
+
if background_task.thread
|
153
|
+
status = background_task.thread.status
|
154
|
+
status = 'complete' if status == false
|
155
|
+
background_task_state_widget = Qt::TableWidgetItem.new(status.to_s)
|
156
|
+
else
|
157
|
+
background_task_state_widget = Qt::TableWidgetItem.new('no thread')
|
158
|
+
end
|
159
|
+
background_task_state_widget.setTextAlignment(Qt::AlignCenter)
|
160
|
+
background_task_state_widget.setSizeHint(Qt::Size.new(80, 30))
|
161
|
+
@background_tasks_table.setItem(row, 1, background_task_state_widget)
|
162
|
+
background_task_status_widget = Qt::TableWidgetItem.new(background_task.status.to_s)
|
163
|
+
background_task_status_widget.setTextAlignment(Qt::AlignCenter)
|
164
|
+
background_task_status_widget.setSizeHint(Qt::Size.new(500, 30))
|
165
|
+
@background_tasks_table.setItem(row, 2, background_task_status_widget)
|
166
|
+
|
167
|
+
row += 1
|
168
|
+
end
|
169
|
+
end
|
170
|
+
@background_tasks_table.displayFullSize
|
171
|
+
background_tasks_layout.addWidget(@background_tasks_table)
|
172
|
+
layout.addWidget(background_tasks_groupbox)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Update the current limits set in the GUI
|
176
|
+
def update_limits_set
|
177
|
+
current_limits_set = System.limits_set.to_s
|
178
|
+
if @limits_set_combo.currentText != current_limits_set
|
179
|
+
known_limits_sets = System.limits.sets
|
180
|
+
known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
|
181
|
+
current_index = known_limits_sets.index(current_limits_set.to_s)
|
182
|
+
@limits_set_combo.clear
|
183
|
+
known_limits_sets.sort.each do |limits_set|
|
184
|
+
@limits_set_combo.addItem(limits_set.to_s)
|
185
|
+
end
|
186
|
+
@limits_set_combo.setCurrentIndex(current_index)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Update the API statistics in the GUI
|
191
|
+
def update_api_status(previous_request_count)
|
192
|
+
if CmdTlmServer.json_drb
|
193
|
+
@api_table.item(0,1).setText(CmdTlmServer.json_drb.num_clients.to_s)
|
194
|
+
@api_table.item(0,2).setText(CmdTlmServer.json_drb.request_count.to_s)
|
195
|
+
request_count = CmdTlmServer.json_drb.request_count
|
196
|
+
requests_per_second = request_count - previous_request_count
|
197
|
+
@api_table.item(0,3).setText(requests_per_second.to_s)
|
198
|
+
previous_request_count = request_count
|
199
|
+
average_request_time = CmdTlmServer.json_drb.average_request_time
|
200
|
+
@api_table.item(0,4).setText(sprintf("%0.6f s", average_request_time))
|
201
|
+
estimated_utilization = requests_per_second * average_request_time * 100.0
|
202
|
+
@api_table.item(0,5).setText(sprintf("%0.2f %", estimated_utilization))
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Update the Ruby system statistics in the GUI
|
207
|
+
def update_system_status
|
208
|
+
@system_table.item(0,0).setText(Thread.list.length.to_s)
|
209
|
+
objs = ObjectSpace.count_objects
|
210
|
+
@system_table.item(0,1).setText(objs[:TOTAL].to_s)
|
211
|
+
@system_table.item(0,2).setText(objs[:FREE].to_s)
|
212
|
+
total = 0
|
213
|
+
objs.each do |key, val|
|
214
|
+
next if key == :TOTAL || key == :FREE
|
215
|
+
total += val
|
216
|
+
end
|
217
|
+
@system_table.item(0,3).setText(total.to_s)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Update the background task status in the GUI
|
221
|
+
def update_background_task_status
|
222
|
+
background_tasks = CmdTlmServer.background_tasks.all
|
223
|
+
if background_tasks.length > 0
|
224
|
+
row = 0
|
225
|
+
background_tasks.each_with_index do |background_task, index|
|
226
|
+
if background_task.thread
|
227
|
+
status = background_task.thread.status
|
228
|
+
status = 'complete' if status == false
|
229
|
+
@background_tasks_table.item(row, 1).setText(status.to_s)
|
230
|
+
else
|
231
|
+
@background_tasks_table.item(row, 1).setText('no thread')
|
232
|
+
end
|
233
|
+
@background_tasks_table.item(row, 2).setText(background_task.status.to_s)
|
234
|
+
row += 1
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
end # module Cosmos
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2014 Ball Aerospace & Technologies Corp.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
|
11
|
+
require 'cosmos'
|
12
|
+
require 'cosmos/gui/qt'
|
13
|
+
|
14
|
+
module Cosmos
|
15
|
+
|
16
|
+
# Implements the targets tab in the Command and Telemetry Server GUI
|
17
|
+
class TargetsTab
|
18
|
+
|
19
|
+
# Create the targets tab and add it to the tab_widget
|
20
|
+
#
|
21
|
+
# @param tab_widget [Qt::TabWidget] The tab widget to add the tab to
|
22
|
+
def populate(tab_widget)
|
23
|
+
num_targets = System.targets.length
|
24
|
+
if num_targets > 0
|
25
|
+
return if num_targets == 1 and System.targets['SYSTEM']
|
26
|
+
num_targets -= 1 if System.targets['SYSTEM']
|
27
|
+
|
28
|
+
scroll = Qt::ScrollArea.new
|
29
|
+
widget = Qt::Widget.new
|
30
|
+
layout = Qt::VBoxLayout.new(widget)
|
31
|
+
# Since the layout will be inside a scroll area make sure it respects the sizes we set
|
32
|
+
layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
|
33
|
+
|
34
|
+
@targets_table = Qt::TableWidget.new()
|
35
|
+
@targets_table.verticalHeader.hide()
|
36
|
+
@targets_table.setRowCount(num_targets)
|
37
|
+
@targets_table.setColumnCount(4)
|
38
|
+
@targets_table.setHorizontalHeaderLabels(["Target Name", "Interface", "Command Count", "Telemetry Count"])
|
39
|
+
|
40
|
+
populate_targets_table()
|
41
|
+
|
42
|
+
@targets_table.displayFullSize
|
43
|
+
|
44
|
+
layout.addWidget(@targets_table)
|
45
|
+
scroll.setWidget(widget)
|
46
|
+
tab_widget.addTab(scroll, "Targets")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Update the targets tab gui
|
51
|
+
def update
|
52
|
+
row = 0
|
53
|
+
System.targets.sort.each do |target_name, target|
|
54
|
+
next if target_name == 'SYSTEM'
|
55
|
+
@targets_table.item(row,2).setText(target.cmd_cnt.to_s)
|
56
|
+
@targets_table.item(row,3).setText(target.tlm_cnt.to_s)
|
57
|
+
row += 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def populate_targets_table
|
64
|
+
row = 0
|
65
|
+
System.targets.sort.each do |target_name, target|
|
66
|
+
next if target_name == 'SYSTEM'
|
67
|
+
target_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(target_name))
|
68
|
+
target_name_widget.setTextAlignment(Qt::AlignCenter)
|
69
|
+
@targets_table.setItem(row, 0, target_name_widget)
|
70
|
+
if target.interface
|
71
|
+
interface_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(target.interface.name.to_s))
|
72
|
+
else
|
73
|
+
interface_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(''))
|
74
|
+
end
|
75
|
+
interface_name_widget.setTextAlignment(Qt::AlignCenter)
|
76
|
+
@targets_table.setItem(row, 1, interface_name_widget)
|
77
|
+
cmd_cnt = Qt::TableWidgetItem.new(Qt::Object.tr(target.cmd_cnt.to_s))
|
78
|
+
cmd_cnt.setTextAlignment(Qt::AlignCenter)
|
79
|
+
@targets_table.setItem(row, 2, cmd_cnt)
|
80
|
+
|
81
|
+
tlm_cnt = Qt::TableWidgetItem.new(Qt::Object.tr(target.tlm_cnt.to_s))
|
82
|
+
tlm_cnt.setTextAlignment(Qt::AlignCenter)
|
83
|
+
@targets_table.setItem(row, 3, tlm_cnt)
|
84
|
+
|
85
|
+
row += 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end # module Cosmos
|
@@ -10,6 +10,7 @@
|
|
10
10
|
|
11
11
|
require 'cosmos'
|
12
12
|
require 'cosmos/config/config_parser'
|
13
|
+
require 'ostruct'
|
13
14
|
|
14
15
|
module Cosmos
|
15
16
|
|
@@ -33,8 +34,9 @@ module Cosmos
|
|
33
34
|
attr_reader :num_columns
|
34
35
|
|
35
36
|
# Processes a file and adds in the configuration defined in the file
|
37
|
+
#
|
38
|
+
# @param filename [String] Name of the configuration file to parse
|
36
39
|
def initialize(filename)
|
37
|
-
# Initialize instance variables
|
38
40
|
@title = 'COSMOS Launcher'
|
39
41
|
@tool_font_settings = ['Arial', 12]
|
40
42
|
@label_font_settings = ['Arial', 16]
|
@@ -42,132 +44,162 @@ module Cosmos
|
|
42
44
|
@items = []
|
43
45
|
|
44
46
|
if File.exist?(filename.to_s)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# Loop over each line of the configuration file
|
51
|
-
parser = ConfigParser.new
|
52
|
-
parser.parse_file(filename) do |keyword, params|
|
53
|
-
# Handle each keyword
|
54
|
-
case keyword
|
55
|
-
|
56
|
-
when 'TOOL'
|
57
|
-
if multitool
|
58
|
-
parser.verify_num_parameters(1, 1, "TOOL <Shell command>")
|
59
|
-
multitool_settings << [:TOOL, format_shell_command(params[0]), true]
|
60
|
-
else
|
61
|
-
parser.verify_num_parameters(2, nil, "TOOL <Button Text> <Shell command> <Icon Filename (optional)> <Parameter Name #1 (optional)> <Parameter Value #1 (optional)> ...")
|
62
|
-
variable_params = nil
|
63
|
-
if params.length > 3
|
64
|
-
raise parser.error("Unbalanced variable params for #{params[0]}") if (params.length % 2) != 1
|
65
|
-
variable_params = []
|
66
|
-
params[3..-1].each_slice(2) { |variable_parameter| variable_params << variable_parameter }
|
67
|
-
end
|
68
|
-
@items << [:TOOL, params[0], format_shell_command(params[1]), true, ConfigParser.handle_nil(params[2]), variable_params]
|
69
|
-
end
|
47
|
+
parse_file(filename)
|
48
|
+
else
|
49
|
+
raise "Launcher configuration file does not exist: #{filename}"
|
50
|
+
end
|
51
|
+
end # def initialize
|
70
52
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
53
|
+
# Create a ConfigParser and parse all the lines in the configuration file
|
54
|
+
#
|
55
|
+
# @param filename [String] Name of the configuration file to parse
|
56
|
+
def parse_file(filename)
|
57
|
+
multitool = nil
|
58
|
+
|
59
|
+
# Loop over each line of the configuration file
|
60
|
+
parser = ConfigParser.new
|
61
|
+
parser.parse_file(filename) do |keyword, params|
|
62
|
+
# Handle each keyword
|
63
|
+
case keyword
|
64
|
+
|
65
|
+
when 'TOOL'
|
66
|
+
parse_tool(parser, params, multitool)
|
67
|
+
|
68
|
+
when 'MULTITOOL_START'
|
69
|
+
parser.verify_num_parameters(1, 2, "MULTITOOL_START <Button Text> <Icon Filename (optional)>")
|
70
|
+
multitool = OpenStruct.new
|
71
|
+
multitool.text = params[0]
|
72
|
+
multitool.icon_filename = ConfigParser.handle_nil(params[1])
|
73
|
+
multitool.icon_filename = 'multi.png' unless multitool.icon_filename
|
74
|
+
multitool.settings = []
|
75
|
+
|
76
|
+
when 'MULTITOOL_END'
|
77
|
+
parser.verify_num_parameters(0, 0, "MULTITOOL_END")
|
78
|
+
raise parser.error("No TOOLs defined within the MULTITOOL") if multitool.settings.select {|setting| setting[0] == :TOOL }.empty?
|
79
|
+
@items << [:MULTITOOL, multitool.text, multitool.settings, true, multitool.icon_filename, nil]
|
80
|
+
multitool = nil
|
81
|
+
|
82
|
+
when 'DELAY'
|
83
|
+
if multitool
|
84
|
+
parser.verify_num_parameters(1, 1, "DELAY <Delay in seconds>")
|
85
|
+
multitool.settings << [:DELAY, Float(params[0]), true]
|
86
|
+
else
|
87
|
+
raise parser.error("DELAY keyword only valid within MULTITOOL")
|
88
|
+
end
|
89
|
+
|
90
|
+
when 'DIVIDER'
|
91
|
+
parser.verify_num_parameters(0, 0, "DIVIDER")
|
92
|
+
@items << [:DIVIDER, nil, nil, nil, nil]
|
93
|
+
|
94
|
+
when 'LABEL'
|
95
|
+
parser.verify_num_parameters(1, 1, "LABEL <Label Text>")
|
96
|
+
@items << [:LABEL, params[0], nil, nil, nil]
|
97
|
+
|
98
|
+
when 'TOOL_FONT', 'LABEL_FONT'
|
99
|
+
usage = "#{keyword} <Font Name> <Font Size>"
|
100
|
+
parser.verify_num_parameters(2, 2, usage)
|
101
|
+
begin
|
102
|
+
@tool_font_settings = [params[0], Integer(params[1])] if keyword == 'TOOL_FONT'
|
103
|
+
@label_font_settings = [params[0], Integer(params[1])] if keyword == 'LABEL_FONT'
|
104
|
+
rescue ArgumentError
|
105
|
+
raise parser.error("#{usage} passed '#{params[0]} #{params[1]}'")
|
106
|
+
end
|
107
|
+
|
108
|
+
when 'TITLE'
|
109
|
+
parser.verify_num_parameters(1, 1, "TITLE <Title Text>")
|
110
|
+
@title = params[0]
|
111
|
+
|
112
|
+
when 'NUM_COLUMNS'
|
113
|
+
usage = "NUM_COLUMNS <Num Columns>"
|
114
|
+
parser.verify_num_parameters(1, 1, usage)
|
115
|
+
begin
|
116
|
+
@num_columns = Integer(params[0])
|
117
|
+
rescue ArgumentError
|
118
|
+
raise parser.error("#{usage} passed '#{params[0]}'")
|
119
|
+
end
|
120
|
+
|
121
|
+
when 'DONT_CAPTURE_IO'
|
122
|
+
parser.verify_num_parameters(0, 0, "DONT_CAPTURE_IO")
|
123
|
+
if multitool
|
124
|
+
if multitool.settings[-1].nil? || multitool.settings[-1][0] != :TOOL
|
125
|
+
raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
|
93
126
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
when 'LABEL'
|
100
|
-
parser.verify_num_parameters(1, 1, "LABEL <Label Text>")
|
101
|
-
@items << [:LABEL, params[0], nil, nil, nil]
|
102
|
-
|
103
|
-
when 'TOOL_FONT'
|
104
|
-
parser.verify_num_parameters(2, 2, "TOOL_FONT <Font Name> <Font Size>")
|
105
|
-
@tool_font_settings = [params[0], Integer(params[1])]
|
106
|
-
|
107
|
-
when 'LABEL_FONT'
|
108
|
-
parser.verify_num_parameters(2, 2, "LABEL_FONT <Font Name> <Font Size>")
|
109
|
-
@label_font_settings = [params[0], Integer(params[1])]
|
110
|
-
|
111
|
-
when 'TITLE'
|
112
|
-
parser.verify_num_parameters(1, 1, "TITLE <Title Text>")
|
113
|
-
@title = params[0]
|
114
|
-
|
115
|
-
when 'NUM_COLUMNS'
|
116
|
-
parser.verify_num_parameters(1, 1, "NUM_COLUMNS <Num Columns>")
|
117
|
-
@num_columns = params[0].to_i
|
118
|
-
|
119
|
-
when 'DONT_CAPTURE_IO'
|
120
|
-
parser.verify_num_parameters(0, 0, "DONT_CAPTURE_IO")
|
121
|
-
if multitool
|
122
|
-
if multitool_settings[-1].nil? || multitool_settings[-1][0] != :TOOL
|
123
|
-
raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
|
124
|
-
end
|
125
|
-
multitool_settings[-1][2] = false
|
126
|
-
else
|
127
|
-
if @items[-1].nil? || @items[-1][0] != :TOOL
|
128
|
-
raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
|
129
|
-
end
|
130
|
-
@items[-1][3] = false
|
127
|
+
multitool.settings[-1][2] = false
|
128
|
+
else
|
129
|
+
if @items[-1].nil? || @items[-1][0] != :TOOL
|
130
|
+
raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
|
131
131
|
end
|
132
|
+
@items[-1][3] = false
|
133
|
+
end
|
132
134
|
|
133
|
-
|
134
|
-
|
135
|
+
else # UNKNOWN
|
136
|
+
raise parser.error("Unknown keyword '#{keyword}'.") if keyword
|
137
|
+
end # case keyword
|
138
|
+
end # parser.parse_file
|
139
|
+
end
|
135
140
|
|
136
|
-
|
141
|
+
protected
|
137
142
|
|
138
|
-
|
143
|
+
def parse_tool(parser, params, multitool)
|
144
|
+
if multitool
|
145
|
+
parser.verify_num_parameters(1, 1, "TOOL <Shell command>")
|
146
|
+
multitool.settings << [:TOOL, format_shell_command(parser, params[0]), true]
|
147
|
+
else
|
148
|
+
parser.verify_num_parameters(2, nil, "TOOL <Button Text> <Shell command> <Icon Filename (optional)> <Parameter Name #1 (optional)> <Parameter Value #1 (optional)> ...")
|
149
|
+
variable_params = nil
|
150
|
+
# Determine if there are parameters which will be displayed in a GUI
|
151
|
+
# dialog when the tool starts
|
152
|
+
if params.length > 3
|
153
|
+
raise parser.error("Unbalanced variable params for #{params[0]}") if (params.length % 2) != 1
|
154
|
+
variable_params = []
|
155
|
+
params[3..-1].each_slice(2) { |variable_parameter| variable_params << variable_parameter }
|
156
|
+
end
|
157
|
+
@items << [:TOOL, params[0], format_shell_command(parser, params[1]), true, ConfigParser.handle_nil(params[2]), variable_params]
|
158
|
+
end
|
159
|
+
end
|
139
160
|
|
161
|
+
def format_shell_command(parser, shell_command)
|
162
|
+
formatted_command = ''
|
163
|
+
case shell_command.split[0]
|
164
|
+
when 'LAUNCH'
|
165
|
+
formatted_command = parse_launch(shell_command)
|
166
|
+
when 'LAUNCH_TERMINAL'
|
167
|
+
formatted_command = parse_launch_terminal(shell_command)
|
140
168
|
else
|
141
|
-
|
169
|
+
# Nothing to do if they aren't using our keywords
|
170
|
+
formatted_command = shell_command
|
142
171
|
end
|
172
|
+
formatted_command
|
173
|
+
end
|
143
174
|
|
144
|
-
|
175
|
+
def parse_launch(command)
|
176
|
+
split = command.split
|
177
|
+
if Kernel.is_mac? and File.exist?(File.join(USERPATH, 'tools', 'mac'))
|
178
|
+
formatted = "open tools/mac/#{split[1]}.app --args #{split[2..-1].join(' ')}".strip
|
179
|
+
else
|
180
|
+
formatted = "RUBYW tools/#{split[1]} #{split[2..-1].join(' ')}".strip
|
181
|
+
end
|
182
|
+
formatted
|
183
|
+
end
|
184
|
+
|
185
|
+
def parse_launch_terminal(command)
|
186
|
+
split = command.split
|
187
|
+
if Kernel.is_mac?
|
188
|
+
formatted = "osascript -e 'tell application \"Terminal\" to do script \"cd #{File.expand_path(USERPATH)} && ruby tools/#{split[1]} #{split[2..-1].join(' ')}\"' -e 'return'"
|
189
|
+
elsif Kernel.is_windows?
|
190
|
+
formatted = "start ruby tools/#{split[1]} #{split[2..-1].join(' ')}".strip
|
191
|
+
else
|
192
|
+
formatted = "gnome-terminal -e \"ruby tools/#{split[1]} #{split[2..-1].join(' ')}\""
|
193
|
+
end
|
145
194
|
|
146
|
-
def format_shell_command(shell_command)
|
147
195
|
if Kernel.is_windows?
|
148
196
|
rubyw_sub = 'rubyw'
|
149
197
|
else
|
150
198
|
rubyw_sub = 'ruby'
|
151
199
|
end
|
152
200
|
|
153
|
-
|
154
|
-
|
155
|
-
if Kernel.is_mac? and File.exist?(File.join(USERPATH, 'tools', 'mac'))
|
156
|
-
shell_command = "open tools/mac/#{split_command[1]}.app --args #{split_command[2..-1].join(' ')}"
|
157
|
-
else
|
158
|
-
shell_command = "RUBYW tools/#{split_command[1]} #{split_command[2..-1].join(' ')}"
|
159
|
-
end
|
160
|
-
elsif split_command[0] == 'LAUNCH_TERMINAL'
|
161
|
-
if Kernel.is_mac?
|
162
|
-
shell_command = "osascript -e 'tell application \"Terminal\" to do script \"cd #{File.expand_path(USERPATH)} && ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}\"' -e 'return'"
|
163
|
-
elsif Kernel.is_windows?
|
164
|
-
shell_command = "start ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}"
|
165
|
-
else
|
166
|
-
shell_command = "gnome-terminal -e \"ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}\""
|
167
|
-
end
|
168
|
-
end
|
169
|
-
shell_command.gsub!('RUBYW', rubyw_sub)
|
170
|
-
shell_command
|
201
|
+
formatted.gsub!('RUBYW', rubyw_sub)
|
202
|
+
formatted
|
171
203
|
end
|
172
204
|
|
173
205
|
end # class LauncherConfig
|