3 #TODO: There are probably instances where I should be quoting variables but am not.
4 #Basically, if there is any chance that an argument will have a space in it, it should
8 OUTPUT
=/tmp
/output.sh.$$
10 trap "rm $OUTPUT; rm $INPUT; exit" SIGHUP SIGINT SIGTERM
12 menu_json
="$(./JSON.sh -l < menu.json)"
13 current_item
="MainMenu"
14 backtitle
="DivinElegy PreCom"
17 dialog_bin
="/usr/bin/dialog"
19 while getopts ":d:" opt
; do
25 echo "Invalid option: -$OPTARG" >&2
29 echo "Option -$OPTARG requires an argument." >&2
41 function get_key_from_line
()
43 key_re
="(.+?)[[:space:]]+\""
44 while read -r line
; do
45 [[ "$1" =~
$key_re ]] && echo ${BASH_REMATCH[1]} && break
49 #Pass something like MainMenu.type and it'll
51 #nice bonus: If passed a full line from menu_json
52 #this will return the value for it
53 function get_value_from_key
()
55 value_re
="[[:space:]]+\"(.+)\"$"
56 while read -r line
; do
57 [[ $line == ${1}* ]] && [[ $line =~
$value_re ]] && echo ${BASH_REMATCH[1]} && break
61 #Helper for short_path_to_full_path
62 #Given a menu item name, and a path to
63 #its parent (a real JSON path like MainMenu.items.0)
64 #this will return the path to the item from the given path
65 #For example if it is passed MainMenu.items.0 and "ITG" it might
68 function get_relative_child_path
()
70 if [[ -z
"$2" ]]; then
73 re
="${2//./\\.}\.items\.([0-9]+?)\.name"
74 while read -r line
; do
75 if [[ "$line" =~
$re ]]; then
76 sub_path
=${BASH_REMATCH[1]}
77 key
=$
(get_key_from_line
"$line")
78 value
=$
(get_value_from_key
"$key")
79 [[ "$value" == "$1" ]] && echo "items.$sub_path"
85 #When talking about menus it's useful to
86 #be able to say something like:
87 #MainMenu.Service.ITG instead of
88 #MainMenu.items.0.items.0
89 #This function converts the nice path
90 #to the real JSON path.
91 function short_path_to_full_path
()
94 while IFS
='.' read -ra parts
; do
95 for i
in "${parts[@]}"; do
96 relative_path
=$
(get_relative_child_path
"$i" "$path_so_far")
98 if [[ -z
"$path_so_far" ]]; then
99 path_so_far
="${relative_path}"
101 path_so_far
="${path_so_far}.${relative_path}"
110 #Functions below here are for convenience.
111 #They allow extraction of information about
112 #menus without having to constantly specifiy
113 #Menu.items.Thing.items.MenuIWant
114 #Instead you can just do Menu.Thing.MenuIWant
116 #Use a dot delim path to the item
117 #returns the type of the item
121 function get_item_type
()
123 full_path
=$
(short_path_to_full_path
"$1")
124 get_value_from_key
"$full_path.type"
127 function get_item_description
()
129 full_path
=$
(short_path_to_full_path
"$1")
130 get_value_from_key
"$full_path.description"
134 function get_item_key
()
136 full_path
=$
(short_path_to_full_path
$1)
137 get_value_from_key
"$full_path.$2"
140 #Returns true if line is a child
141 #of the dot-delim menu passed in
143 #note: child means _direct_ child
144 #this will exclude grandchildren etc
145 function is_item_of_menu
()
147 full_path
=$
(short_path_to_full_path
"$2")
149 items_in_path
=$
(grep -o items
<<< "$full_path" |
wc -l
)
150 items_in_line
=$
(grep -o items
<<< "$1" |
wc -l
)
152 if [[ $1 == ${full_path}* ]] && [[ $
((items_in_path
+ 1)) == $items_in_line ]]; then
159 function is_child_of
()
161 if [[ $1 == ${2}* ]]; then
169 function get_adapter_detail
()
171 value_re
="# ${2}:[[:space:]]+(.+)$"
173 while read -r line
; do
174 [[ $line =~
$value_re ]] && echo ${BASH_REMATCH[1]} && break
178 #Use a dot delimited path to the menu
181 # MainMenu.Services.Streaming
182 function render_menu
()
185 while read -r line
; do
186 #Cracks the shits without the quotes on the args,
188 #Yes I do, it's because $line has a tab followed by text in it.
189 #Without the quotes it thinks what follows the tab is the second arg
190 if is_item_of_menu
"$line" "$1"; then
191 #Match on name as it is unique per item
192 #Multiple lines will match per item without this
193 name_re
=".name[[:space:]].+?\"(.+)\""
194 if [[ $line =~
$name_re ]]; then
195 key
=$
(get_key_from_line
"$line")
196 desc
=$
(get_value_from_key
"${key%.*}.description")
197 name
=$
(get_value_from_key
"${key%.*}.name")
198 options
+=("$name" "$desc")
201 done <<< "$menu_json"
203 if [[ $1 == "MainMenu" ]]; then
204 options
+=("Quit" "Exit the menu masterqueef")
206 options
+=("Back" "Go back")
209 #Also cracks the shits without quotes.
210 #Also don't know why.
211 $dialog_bin --clear --backtitle
"$backtitle" --title
"${1//./>}" --nocancel
--menu
"$(get_item_description $1)" "$box_height" "$box_width" 4 "${options[@]}" 2>"${INPUT}"
214 function toggle_service
()
216 service_command
=$
(get_item_key
$1 command)
217 service_name
=$
(basename $service_command)
219 #If the quotes aren't here then the application launches
221 pid
="$(pgrep $service_name)"
223 #XXX: Eww. Too many ifs. Clean this?
225 if [[ "$2" != "skip_confirmation_dialogs" ]]; then
228 $dialog_bin --clear --backtitle
"$backtitle" --title
"Disable $service_name" --yesno
"This will stop $service_name. Are you sure?" 6 50
229 [[ $?
== 0 ]] && kill -9 $pid
232 if [[ "$2" == "skip_confirmation_dialogs" ]]; then
233 $service_command > /dev
/null
2>&1 &
235 $dialog_bin --clear --backtitle
"$backtitle" --title
"Enable $service_name" --yesno
"This will start $service_name. Are you sure?" 6 50
236 [[ $?
== 0 ]] && $service_command > /dev
/null
2>&1 &
240 #Kind of a hack? When we get here current_item will be:
241 #thing.otherThing.this_service
242 #but after we leave here we want to render thing.otherThing
243 #so returning Back gets the main loop to do that.
244 echo "Back" > "${INPUT}"
249 #I tried $(short_path_to_full_path $1).commands
250 #but it produced a weird result.
251 local full_path
=$
(short_path_to_full_path
"$1")
253 while read -r line
; do
254 if is_child_of
"$line" "${full_path}.commands"; then
255 command_re
=".\/(.+.sh)"
256 if [[ $line =~
$command_re ]]; then
257 widget
=$
(get_adapter_detail
"${BASH_REMATCH[1]}" "widget")
258 key
=$
(get_key_from_line
"$line")
259 command="$(get_value_from_key $key)"
260 title
=$
(get_value_from_key
"${key%.*}.title")
263 gauge
) eval "$command" |
$dialog_bin --clear --backtitle
"$backtitle" --title
"Running $1" --gauge
"$title" 6 60;;
264 msgbox
) [[ $2 != "skip_confirmation_dialogs" ]] && eval "$command" |
$dialog_bin --clear --backtitle
"$backtitle" --title
"$title" --msgbox
"$(eval \"$command\")" 8 40;;
268 done <<< "$menu_json"
270 echo "Back" > "${INPUT}"
273 function run_preset
()
275 local full_path
=$
(short_path_to_full_path
"$1")
276 while read -r line
; do
277 if is_child_of
"$line" "${full_path}.itemsToRun"; then
278 key
=$
(get_key_from_line
"$line")
279 item
=$
(get_value_from_key
"$key")
280 process_item
"$item" "skip_confirmation_dialogs"
282 done <<< "$menu_json"
284 echo "Back" > "${INPUT}"
287 function process_item
()
289 type=$
(get_item_type
"$1")
291 menu
) render_menu
"$1" "$2";;
292 service
) toggle_service
"$1" "$2";;
293 task
) run_task
"$1" "$2";;
294 preset
) run_preset
"$1" "$2";;
303 process_item
"$current_item"
304 #todo: Is it possible to avoid using a file for this?
305 selection
=$
(<"${INPUT}")
309 Back
) current_item
="${current_item%.*}";;
310 *) current_item
="$current_item.$selection";;
319 [[ -f
$OUTPUT ]] && rm $OUTPUT
320 [[ -f
$INPUT ]] && rm $INPUT