183 lines
10 KiB
Bash
183 lines
10 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/
|
||
|
|
||
|
function cli_entrypoint() {
|
||
|
# array, readonly, global, for future reference, "exported" to shutup shellcheck
|
||
|
declare -rg -x -a ARMBIAN_ORIGINAL_ARGV=("${@}")
|
||
|
|
||
|
if [[ "${ARMBIAN_ENABLE_CALL_TRACING}" == "yes" ]]; then
|
||
|
set -T # inherit return/debug traps
|
||
|
mkdir -p "${SRC}"/output/call-traces
|
||
|
echo -n "" > "${SRC}"/output/call-traces/calls.txt
|
||
|
# See https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
|
||
|
trap 'echo "${FUNCNAME[*]}|${BASH_LINENO[*]}|${BASH_SOURCE[*]}|${LINENO}" >> ${SRC}/output/call-traces/calls.txt ;' RETURN
|
||
|
fi
|
||
|
|
||
|
# @TODO: allow for a super-early userpatches/config-000.custom.conf.sh to be loaded, before anything else.
|
||
|
# This would allow for custom commands and interceptors.
|
||
|
|
||
|
# Decide what we're gonna do. We've a few hardcoded, 1st-argument "commands".
|
||
|
declare -g -A ARMBIAN_COMMANDS_TO_HANDLERS_DICT ARMBIAN_COMMANDS_TO_VARS_DICT
|
||
|
armbian_register_commands # this defines the above two dictionaries
|
||
|
|
||
|
# Process the command line, separating params (XX=YY) from non-params arguments.
|
||
|
# That way they can be set in any order.
|
||
|
declare -A -g ARMBIAN_PARSED_CMDLINE_PARAMS=() # A dict of PARAM=VALUE
|
||
|
declare -a -g ARMBIAN_NON_PARAM_ARGS=() # An array of all non-param arguments
|
||
|
parse_cmdline_params "${@}" # which fills the above vars.
|
||
|
|
||
|
# Now load the key=value pairs from cmdline into environment, before loading config or executing commands.
|
||
|
# This will be done _again_ later, to make sure cmdline params override config et al.
|
||
|
apply_cmdline_params_to_env "early" # which uses ARMBIAN_PARSED_CMDLINE_PARAMS
|
||
|
# From here on, no more ${1} or stuff. We've parsed it all into ARMBIAN_PARSED_CMDLINE_PARAMS or ARMBIAN_NON_PARAM_ARGS and ARMBIAN_COMMAND.
|
||
|
|
||
|
# Re-initialize logging, to take into account the new environment after parsing cmdline params.
|
||
|
logging_init
|
||
|
|
||
|
declare -a -g ARMBIAN_CONFIG_FILES=() # fully validated, complete paths to config files.
|
||
|
declare -g ARMBIAN_COMMAND_HANDLER="" ARMBIAN_COMMAND="" ARMBIAN_COMMAND_VARS="" # only valid command and handler will ever be set here.
|
||
|
declare -g ARMBIAN_HAS_UNKNOWN_ARG="no" # if any unknown params, bomb.
|
||
|
for argument in "${ARMBIAN_NON_PARAM_ARGS[@]}"; do # loop over all non-param arguments, find commands and configs.
|
||
|
parse_each_cmdline_arg_as_command_param_or_config "${argument}" # sets all the vars above
|
||
|
done
|
||
|
|
||
|
# More sanity checks.
|
||
|
# If unknowns, bail.
|
||
|
if [[ "${ARMBIAN_HAS_UNKNOWN_ARG}" == "yes" ]]; then
|
||
|
exit_with_error "Unknown arguments found. Please check the output above and fix them."
|
||
|
fi
|
||
|
|
||
|
# @TODO: Have a config that is always included? "${SRC}/userpatches/config-default.conf" ?
|
||
|
|
||
|
# If we don't have a command decided yet, use the undecided command.
|
||
|
if [[ "${ARMBIAN_COMMAND}" == "" ]]; then
|
||
|
display_alert "No command found, using default" "undecided" "debug"
|
||
|
ARMBIAN_COMMAND="undecided"
|
||
|
fi
|
||
|
|
||
|
# If we don't have a command at this stage, we should default either to 'build' or 'docker', depending on OS.
|
||
|
# Give the chosen command a chance to refuse running, or, even, change the final command to run.
|
||
|
# This allows for example the 'build' command to auto-launch under docker, even without specifying it.
|
||
|
# Also allows for launchers to keep themselves when re-launched, yet do something diferent. (eg: docker under docker does build).
|
||
|
# Or: build under Darwin does docker...
|
||
|
# each _pre_run can change the command and vars to run too, so do it in a loop until it stops changing.
|
||
|
declare -g ARMBIAN_CHANGE_COMMAND_TO="${ARMBIAN_COMMAND}"
|
||
|
while [[ "${ARMBIAN_CHANGE_COMMAND_TO}" != "" ]]; do
|
||
|
display_alert "Still a command to pre-run, this time:" "${ARMBIAN_CHANGE_COMMAND_TO}" "debug"
|
||
|
|
||
|
declare -g ARMBIAN_COMMAND_REQUIRE_BASIC_DEPS="no" # reset this before every pre_run, so only the last one wins.
|
||
|
ARMBIAN_COMMAND="${ARMBIAN_CHANGE_COMMAND_TO}"
|
||
|
armbian_prepare_cli_command_to_run "${ARMBIAN_COMMAND}"
|
||
|
|
||
|
ARMBIAN_CHANGE_COMMAND_TO=""
|
||
|
armbian_cli_pre_run_command
|
||
|
done
|
||
|
|
||
|
# IMPORTANT!!!: it is INVALID to relaunch compile.sh from here. It will cause logging mistakes.
|
||
|
# So the last possible moment to relaunch is in xxxxx_pre_run!
|
||
|
# Also form here, UUID will be generated, output created, logging enabled, etc.
|
||
|
|
||
|
# Init basic dirs.
|
||
|
declare -g -r DEST="${SRC}/output" USERPATCHES_PATH="${SRC}"/userpatches # DEST is the main output dir, and USERPATCHES_PATH is the userpatches dir. read-only.
|
||
|
mkdir -p "${DEST}" "${USERPATCHES_PATH}" # Create output and userpatches directory if not already there
|
||
|
display_alert "Output directory created! DEST:" "${DEST}" "debug"
|
||
|
|
||
|
# set unique mounting directory for this execution.
|
||
|
# basic deps, which include "uuidgen", will be installed _after_ this, so we gotta tolerate it not being there yet.
|
||
|
declare -g ARMBIAN_BUILD_UUID
|
||
|
if [[ "${ARMBIAN_BUILD_UUID}" != "" ]]; then
|
||
|
display_alert "Using passed-in ARMBIAN_BUILD_UUID" "${ARMBIAN_BUILD_UUID}" "debug"
|
||
|
else
|
||
|
if command -v uuidgen 1> /dev/null; then
|
||
|
ARMBIAN_BUILD_UUID="$(uuidgen)"
|
||
|
else
|
||
|
display_alert "uuidgen not found" "uuidgen not installed yet" "info"
|
||
|
ARMBIAN_BUILD_UUID="no-uuidgen-yet-${RANDOM}-$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))"
|
||
|
fi
|
||
|
display_alert "Generated ARMBIAN_BUILD_UUID" "${ARMBIAN_BUILD_UUID}" "debug"
|
||
|
fi
|
||
|
declare -g -r ARMBIAN_BUILD_UUID="${ARMBIAN_BUILD_UUID}" # Make read-only
|
||
|
display_alert "Build UUID:" "${ARMBIAN_BUILD_UUID}" "debug"
|
||
|
|
||
|
# Super-global variables, used everywhere. The directories are NOT _created_ here, since this very early stage. They are all readonly, for sanity.
|
||
|
declare -g -r WORKDIR_BASE_TMP="${SRC}/.tmp" # a.k.a. ".tmp" dir. it is a shared base dir for all builds, but each build gets its own WORKDIR/TMPDIR.
|
||
|
|
||
|
declare -g -r WORKDIR="${WORKDIR_BASE_TMP}/work-${ARMBIAN_BUILD_UUID}" # WORKDIR at this stage. It will become TMPDIR later. It has special significance to `mktemp` and others!
|
||
|
declare -g -r LOGDIR="${WORKDIR_BASE_TMP}/logs-${ARMBIAN_BUILD_UUID}" # Will be initialized very soon, literally, below.
|
||
|
declare -g -r EXTENSION_MANAGER_TMP_DIR="${WORKDIR_BASE_TMP}/extensions-${ARMBIAN_BUILD_UUID}" # EXTENSION_MANAGER_TMP_DIR used to store extension-composed functions
|
||
|
|
||
|
# @TODO: These are used only by rootfs/image actual build, move there...
|
||
|
declare -g -r SDCARD="${WORKDIR_BASE_TMP}/rootfs-${ARMBIAN_BUILD_UUID}" # SDCARD (which is NOT an sdcard, but will be, maybe, one day) is where we work the rootfs before final imaging. "rootfs" stage.
|
||
|
declare -g -r MOUNT="${WORKDIR_BASE_TMP}/mount-${ARMBIAN_BUILD_UUID}" # MOUNT ("mounted on the loop") is the mounted root on final image (via loop). "image" stage
|
||
|
declare -g -r DESTIMG="${WORKDIR_BASE_TMP}/image-${ARMBIAN_BUILD_UUID}" # DESTIMG is where the backing image (raw, huge, sparse file) is kept (not the final destination)
|
||
|
|
||
|
# Make sure ARMBIAN_LOG_CLI_ID is set, and unique, and readonly.
|
||
|
# Pre-runs might change it before this, but if not set, default to ARMBIAN_COMMAND.
|
||
|
declare -r -g ARMBIAN_LOG_CLI_ID="${ARMBIAN_LOG_CLI_ID:-${ARMBIAN_COMMAND}}"
|
||
|
|
||
|
# If we're on Linux & root, mount tmpfs on LOGDIR. This has it's own cleanup handler.
|
||
|
# It also _creates_ the LOGDIR, and the cleanup handler will delete.
|
||
|
prepare_tmpfs_for "LOGDIR" "${LOGDIR}"
|
||
|
|
||
|
LOG_SECTION="entrypoint" start_logging_section # This will create LOGDIR if it does not exist. @TODO: also maybe causes a spurious group to be created in the log file
|
||
|
add_cleanup_handler trap_handler_cleanup_logging # cleanup handler for logs; it rolls it up from LOGDIR into DEST/logs
|
||
|
add_cleanup_handler trap_handler_reset_output_owner # make sure output folder is owned by pre-sudo/pre-Docker user if that's the case
|
||
|
|
||
|
# @TODO: So gigantic contention point here about logging the basic deps installation.
|
||
|
if [[ "${ARMBIAN_COMMAND_REQUIRE_BASIC_DEPS}" == "yes" ]]; then
|
||
|
if [[ "${OFFLINE_WORK}" == "yes" ]]; then
|
||
|
display_alert "* " "You are working offline!"
|
||
|
display_alert "* " "Sources, time and host will not be checked"
|
||
|
else
|
||
|
# check and install the basic utilities;
|
||
|
LOG_SECTION="prepare_host_basic" do_with_logging prepare_host_basic # This includes the 'docker' case.
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Legacy. We used to source the extension manager here, but now it's included in the library.
|
||
|
# @TODO: a quick check on the globals in extensions.sh would get rid of this.
|
||
|
extension_manager_declare_globals
|
||
|
|
||
|
# Loop over the ARMBIAN_CONFIG_FILES array and source each. The order is important.
|
||
|
for config_file in "${ARMBIAN_CONFIG_FILES[@]}"; do
|
||
|
local config_filename="${config_file##*/}" config_dir="${config_file%/*}"
|
||
|
display_alert "Sourcing config file" "${config_filename}" "debug"
|
||
|
|
||
|
# use pushd/popd to change directory to the config file's directory, so that relative paths in the config file work.
|
||
|
pushd "${config_dir}" > /dev/null || exit_with_error "Failed to pushd to ${config_dir}"
|
||
|
|
||
|
# shellcheck source=/dev/null
|
||
|
LOG_SECTION="userpatches_config:${config_filename}" do_with_logging source "${config_file}"
|
||
|
|
||
|
# reset completely after sourcing config file
|
||
|
set -e
|
||
|
#set -o pipefail # trace ERR through pipes - will be enabled "soon"
|
||
|
#set -o nounset ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled
|
||
|
set -o errtrace # trace ERR through - enabled
|
||
|
set -o errexit ## set -e : exit the script if any statement returns a non-true return value - enabled
|
||
|
|
||
|
popd > /dev/null || exit_with_error "Failed to popd from ${config_dir}"
|
||
|
|
||
|
# Apply the params received from the command line _again_ after running the config.
|
||
|
# This ensures that params take precedence over stuff possibly defined in the config.
|
||
|
apply_cmdline_params_to_env "after config '${config_filename}'" # which uses ARMBIAN_PARSED_CMDLINE_PARAMS
|
||
|
done
|
||
|
|
||
|
# Early check for deprecations
|
||
|
error_if_lib_tag_set # make sure users are not thrown off by using old parameter which does nothing anymore; explain
|
||
|
|
||
|
display_alert "Executing final CLI command" "${ARMBIAN_COMMAND}" "debug"
|
||
|
armbian_cli_run_command
|
||
|
display_alert "Done Executing final CLI command" "${ARMBIAN_COMMAND}" "debug"
|
||
|
|
||
|
# Build done, run the cleanup handlers explicitly.
|
||
|
# This zeroes out the list of cleanups, so it"s not done again when the main script exits normally and trap = 0 runs.
|
||
|
run_cleanup_handlers
|
||
|
}
|