269 lines
12 KiB
Bash
269 lines
12 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# Copyright (c) 2013-2023 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 -g -r backtitle="Armbian building script, https://www.armbian.com | https://docs.armbian.com | (c) 2013-2023 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() {
|
|
eval "$1"='$2'
|
|
eval "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(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 interactive_config_ask_branch() {
|
|
# if BRANCH not set, display selection menu
|
|
if [[ -n $BRANCH ]]; then
|
|
display_alert "Already set BRANCH, skipping interactive" "${BRANCH}" "debug"
|
|
return 0
|
|
fi
|
|
declare -a options=()
|
|
# Loop over the kernel targets and add them to the options array. They're comma separated.
|
|
declare one_kernel_target
|
|
for one_kernel_target in $(echo "${KERNEL_TARGET}" | tr "," "\n"); do
|
|
case $one_kernel_target in
|
|
"current")
|
|
options+=("current" "Recommended. Usually an LTS kernel")
|
|
;;
|
|
"legacy")
|
|
options+=("legacy" "Old stable / Legacy / Vendor kernel")
|
|
;;
|
|
"edge")
|
|
options+=("edge" "Bleeding edge / latest possible")
|
|
;;
|
|
*)
|
|
options+=("${one_kernel_target}" "Experimental ${one_kernel_target} kernel / for Developers")
|
|
;;
|
|
esac
|
|
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
|
|
}
|