-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Expand file tree
/
Copy pathinteractive.sh
More file actions
327 lines (287 loc) · 13.3 KB
/
interactive.sh
File metadata and controls
327 lines (287 loc) · 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/usr/bin/env bash
#
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2013-2026 Igor Pecovnik, igor@armbian.com
#
# This file is a part of the Armbian Build Framework
# https://github.com/armbian/build/
#!/usr/bin/env bash
function interactive_config_prepare_terminal() {
if [[ -z $ROOT_FS_CREATE_ONLY ]]; then
if [[ -t 0 ]]; then # "-t fd return True if file descriptor fd is open and refers to a terminal". 0 = stdin, 1 = stdout, 2 = stderr, 3+ custom
# override stty size, if stdin is a terminal.
[[ -n $COLUMNS ]] && stty cols $COLUMNS
[[ -n $LINES ]] && stty rows $LINES
declare -g TTY_X=$(($(stty size | awk '{print $2}') - 6)) # determine terminal width
declare -g TTY_Y=$(($(stty size | awk '{print $1}') - 6)) # determine terminal height
fi
fi
# We'll use this title on all menus
declare current_year
current_year=$(date +%Y)
declare -g -r backtitle="Armbian Linux build framework, https://www.armbian.com | (c) 2013-${current_year} Igor Pecovnik "
declare -A -g ARMBIAN_INTERACTIVE_CONFIGS=() # An associative array of all interactive configurations
}
# Set config variable and ARMBIAN_INTERACTIVE_CONFIGS in a consistent way
# $1: variable name
# $2: variable value
function set_interactive_config_value() {
declare -g "${1}=${2}"
ARMBIAN_INTERACTIVE_CONFIGS["${1}"]="${2}"
}
function interactive_finish() {
unset TTY_X
unset TTY_Y
unset options
unset DIALOG_EXIT_CODE
unset WIP_STATE
unset SHOW_WARNING
}
function interactive_config_ask_kernel() {
interactive_config_ask_kernel_configure
}
function interactive_config_ask_kernel_configure() {
[[ -n ${KERNEL_CONFIGURE} ]] && return 0
options+=("no" "Do not change the kernel configuration")
options+=("yes" "Show a kernel configuration menu before compilation")
#options+=("prebuilt" "Use precompiled packages (maintained hardware only)") # @TODO armbian-next does not support this, I think.
dialog_if_terminal_set_vars --title "Choose an option" --backtitle "$backtitle" --no-tags --menu "Select the kernel configuration" $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}"
set_interactive_config_value KERNEL_CONFIGURE "${DIALOG_RESULT}"
[[ ${DIALOG_EXIT_CODE} != 0 ]] && exit_with_error "You cancelled interactive during kernel configuration" "Build cancelled"
unset options
}
# Required usage:
# declare -a arr_all_board_names=() arr_all_board_options=() # arrays
# declare -A dict_all_board_types=() dict_all_board_source_files=() dict_all_board_descriptions=() # dictionaries
# get_list_of_all_buildable_boards arr_all_board_names arr_all_board_options dict_all_board_types dict_all_board_source_files dict_all_board_descriptions # invoke
function get_list_of_all_buildable_boards() {
display_alert "Generating list of all available boards" "might take a while" ""
local -a board_types=("conf")
[[ "${WIP_STATE}" != "supported" ]] && board_types+=("wip" "csc" "eos" "tvb")
local -a board_file_paths=("${SRC}/config/boards" "${USERPATCHES_PATH}/config/boards")
# local -n is a name reference, see https://www.linuxjournal.com/content/whats-new-bash-parameter-expansion
# it works with arrays and associative arrays/dictionaries
local -n ref_arr_all_board_names="${1}"
[[ "${2}" != "" ]] && local -n ref_arr_all_board_options="${2}" # optional
local -n ref_dict_all_board_types="${3}"
local -n ref_dict_all_board_source_files="${4}"
[[ "${5}" != "" ]] && local -n ref_dict_all_board_descriptions="${5}" # optional
declare -i prepare_options=0
if [[ "${2}" != "" || "${5}" != "" ]]; then # only if second or fifth reference specified, otherwise too costly
prepare_options=1
fi
local board_file_path board_type full_board_file
for board_file_path in "${board_file_paths[@]}"; do
[[ ! -d "${board_file_path}" ]] && continue
for board_type in "${board_types[@]}"; do
for full_board_file in "${board_file_path}"/*."${board_type}"; do
[[ "${full_board_file}" == *"*"* ]] && continue # ignore non-matches, due to bash's (non-)globbing behaviour
local board_name board_desc
board_name="$(basename "${full_board_file}" | cut -d'.' -f1)"
ref_dict_all_board_types["${board_name}"]="${board_type}"
ref_dict_all_board_source_files["${board_name}"]="${ref_dict_all_board_source_files["${board_name}"]} ${full_board_file}" # accumulate, will have extra space
if [[ ${prepare_options} -gt 0 ]]; then
board_desc="$(head -1 "${full_board_file}" | cut -d'#' -f2)"
ref_dict_all_board_descriptions["${board_name}"]="${board_desc}"
fi
done
done
done
if [[ ${prepare_options} -gt 0 ]]; then
# get a sorted list of boards across all types
declare ref_arr_all_board_names_unsorted=("${!ref_dict_all_board_types[@]}") # Expand the keys of one of the dicts, that's the list of boards (unsorted)
declare -a ref_arr_all_board_names_sorted=()
readarray -t ref_arr_all_board_names_sorted < <(printf '%s\n' "${ref_arr_all_board_names_unsorted[@]}" | sort -h)
ref_arr_all_board_names=("${ref_arr_all_board_names_sorted[@]}")
# prepare the options for the dialog menu; this is sorted the same order as the boards.
for board_name in "${ref_arr_all_board_names[@]}"; do
ref_arr_all_board_options+=("${board_name}" "\Z1(${ref_dict_all_board_types["${board_name}"]})\Zn ${ref_dict_all_board_descriptions["${board_name}"]}")
done
else
ref_arr_all_board_names=("${!ref_dict_all_board_types[@]}") # Expand the keys of one of the dicts, that's the list of boards (unsorted)
fi
return 0
}
function interactive_config_ask_board_list() {
# if BOARD is not set, display selection menu, otherwise return success
[[ -n ${BOARD} ]] && return 0
declare WIP_STATE=supported
if [[ "${EXPERT}" == "yes" ]]; then
display_alert "Expert mode!" "You can select all boards" "info"
WIP_STATE=unsupported
fi
declare WIP_BUTTON='CSC/WIP/EOS/TVB'
declare STATE_DESCRIPTION=' - boards with high level of software maturity'
declare temp_rc
temp_rc=$(mktemp) # @TODO: this is a _very_ early call to mktemp - no TMPDIR set yet - it needs to be cleaned-up somehow
while true; do
declare -a arr_all_board_names=() arr_all_board_options=() # arrays
declare -A dict_all_board_types=() dict_all_board_source_files=() dict_all_board_descriptions=() # dictionaries
get_list_of_all_buildable_boards arr_all_board_names arr_all_board_options dict_all_board_types dict_all_board_source_files dict_all_board_descriptions # invoke
echo > "${temp_rc}" # zero out the rcfile to start
if [[ $WIP_STATE != supported ]]; then # be if wip csc etc included. I personally disagree here.
cat <<- 'EOF' > "${temp_rc}"
dialog_color = (RED,WHITE,OFF)
screen_color = (WHITE,RED,ON)
tag_color = (RED,WHITE,ON)
item_selected_color = (WHITE,RED,ON)
tag_selected_color = (WHITE,RED,ON)
tag_key_selected_color = (WHITE,RED,ON)
EOF
fi
DIALOGRC=$temp_rc \
dialog_if_terminal_set_vars --title "Choose a board" --backtitle "$backtitle" --scrollbar \
--colors --extra-label "Show $WIP_BUTTON" --extra-button \
--menu "Select the target board. Displaying:\n$STATE_DESCRIPTION" $TTY_Y $TTY_X $((TTY_Y - 8)) "${arr_all_board_options[@]}"
set_interactive_config_value BOARD "${DIALOG_RESULT}"
declare STATUS=${DIALOG_EXIT_CODE}
if [[ $STATUS == 3 ]]; then
if [[ $WIP_STATE == supported ]]; then
[[ $SHOW_WARNING == yes ]] && show_developer_warning
STATE_DESCRIPTION=' - \Z1(conf)\Zn - Boards with high level of software maturity
\n - \Z1(CSC)\Zn - Community Supported Configuration\n - \Z1(WIP)\Zn - Work In Progress
\n - \Z1(EOS)\Zn - End Of Support\n - \Z1(TVB)\Zn - TV boxes'
WIP_STATE=unsupported
WIP_BUTTON='matured'
EXPERT=yes
else
STATE_DESCRIPTION=' - boards with high level of software maturity'
WIP_STATE=supported
WIP_BUTTON='CSC/WIP/EOS'
EXPERT=no # @TODO: this overrides an "expert" mode that could be set on by the user. revert to original one?
fi
continue
elif [[ $STATUS == 0 ]]; then
break
else
exit_with_error "You cancelled interactive config" "Build cancelled, board not chosen"
fi
done
}
function get_kernel_info_for_branch() {
local search_branch="$1"
local conf_file="${SRC}/config/sources/families/${BOARDFAMILY}.conf"
awk -v branch="$search_branch" '
BEGIN { found=0; major_minor=""; desc="" }
/^[[:space:]]*[a-zA-Z0-9_-]+\)/ {
if ($0 ~ "^[[:space:]]*" branch "\\)") {
found=1
next
} else if (found) {
exit
}
}
found && /declare[[:space:]]+-g[[:space:]]+KERNEL_MAJOR_MINOR=/ {
if (match($0, /"([^"]+)"/, arr)) {
major_minor=arr[1]
}
}
found && /declare[[:space:]]+-g[[:space:]]+KERNEL_DESCRIPTION=/ {
if (match($0, /"([^"]+)"/, arr)) {
desc=arr[1]
}
}
END {
print major_minor "|" desc
}
' "$conf_file"
}
function interactive_config_ask_branch() {
if [[ -n $BRANCH ]]; then
display_alert "Already set BRANCH, skipping interactive" "${BRANCH}" "debug"
return 0
fi
declare -a options=()
declare one_kernel_target
for one_kernel_target in $(echo "${KERNEL_TARGET}" | tr "," "\n"); do
local version=""
local description=""
local info
info="$(get_kernel_info_for_branch "$one_kernel_target")"
version="${info%%|*}"
description="${info#*|}"
# Fallback if description is empty
if [[ -z "$description" ]]; then
case "$one_kernel_target" in
current)
description="Recommended. Usually an LTS kernel"
;;
legacy)
description="Old stable / Legacy kernel"
;;
edge)
description="Bleeding edge / latest possible"
;;
cloud)
description="Cloud optimized minimal LTS kernel"
;;
vendor)
description="Vendor BSP kernel"
;;
*)
description="Experimental ${one_kernel_target} kernel / for Developers"
;;
esac
fi
# Append version if found
if [[ -n "$version" ]]; then
description="${description} (${version})"
fi
options+=("${one_kernel_target}" "${description}")
done
dialog_if_terminal_set_vars --title "Choose a kernel" --backtitle "$backtitle" --colors \
--menu "Select the target kernel branch.\nSelected BOARD='${BOARD}'\nExact kernel versions depend on selected board and its family." \
$TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}"
set_interactive_config_value BRANCH "${DIALOG_RESULT}"
[[ -z ${BRANCH} ]] && exit_with_error "No kernel branch selected"
return 0
}
function interactive_config_ask_release() {
[[ -n ${RELEASE} ]] && return 0
declare -a options=()
distros_options
dialog_if_terminal_set_vars --title "Choose a release package base" --backtitle "$backtitle" --menu "Select the target OS release package base; selected BRANCH='${BRANCH}'" $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}"
set_interactive_config_value RELEASE "${DIALOG_RESULT}"
[[ -z ${RELEASE} ]] && exit_with_error "No release selected"
return 0 # shortcircuit above!
}
function interactive_config_ask_desktop_build() {
# don't show desktop option if we choose minimal build
[[ $HAS_VIDEO_OUTPUT == no || $BUILD_MINIMAL == yes ]] && BUILD_DESKTOP=no
[[ -n ${BUILD_DESKTOP} ]] && return 0
# read distribution support status which is written to the armbian-release file
set_distribution_status
options=()
options+=("no" "Image with console interface (server)")
options+=("yes" "Image with desktop environment")
dialog_if_terminal_set_vars --title "Choose image type" --backtitle "$backtitle" --no-tags \
--menu "Select the target image type" $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}"
set_interactive_config_value BUILD_DESKTOP "${DIALOG_RESULT}"
unset options
[[ -z $BUILD_DESKTOP ]] && exit_with_error "No image type selected"
if [[ ${BUILD_DESKTOP} == "yes" ]]; then
set_interactive_config_value BUILD_MINIMAL no
SELECTED_CONFIGURATION="desktop"
fi
return 0
}
function interactive_config_ask_standard_or_minimal() {
[[ "${BUILDING_IMAGE}" != "yes" ]] && return 0
[[ $BUILD_DESKTOP != no ]] && return 0
[[ -n $BUILD_MINIMAL ]] && return 0
options=()
options+=("no" "Standard image with console interface")
options+=("yes" "Minimal image with console interface")
dialog_if_terminal_set_vars --title "Choose image type" --backtitle "$backtitle" --no-tags \
--menu "Select the target image type" $TTY_Y $TTY_X $((TTY_Y - 8)) "${options[@]}"
set_interactive_config_value BUILD_MINIMAL "${DIALOG_RESULT}"
unset options
[[ -z $BUILD_MINIMAL ]] && exit_with_error "No standard/minimal selected"
if [[ $BUILD_MINIMAL == "yes" ]]; then
SELECTED_CONFIGURATION="cli_minimal"
else
SELECTED_CONFIGURATION="cli_standard"
fi
return 0
}