1086 lines
42 KiB
Bash
Executable File
1086 lines
42 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -u
|
|
|
|
##### BASIC RUNTIME VALIDATION #########################################################################################
|
|
# shellcheck disable=SC2128
|
|
if [ -z "${BASH_SOURCE}" ] ; then
|
|
echo "You need to execute this script using bash v4+ without using pipes"
|
|
exit 1
|
|
fi
|
|
|
|
cd "${BASH_SOURCE%/*}/" || exit 1
|
|
########################################################################################################################
|
|
|
|
##### CONFIGURATION YOU CAN OVERRIDE USING ENVIRONMENT #################################################################
|
|
readonly BRP_DEBUG=${BRP_DEBUG:-0} # whether you want to see debug messages
|
|
readonly MRP_SRC_NAME=${MRP_SRC_NAME:-$(basename "$0")}
|
|
readonly RPT_EXTS_DIR=${RPT_EXTS_DIR:-"$PWD/custom/extensions"}
|
|
########################################################################################################################
|
|
|
|
##### INCLUDES #########################################################################################################
|
|
. include/log.sh # logging helpers
|
|
. include/text.sh # text manipulation
|
|
. include/runtime.sh # need to include this early so we can used date and such
|
|
. include/json.sh # json parsing routines
|
|
. include/file.sh # file-related operations (copying/moving/unpacking etc)
|
|
. include/patch.sh # helpers for creating *.sh from template
|
|
########################################################################################################################
|
|
|
|
|
|
# Validates extension ID
|
|
#
|
|
# Args: $1 ID of an extension
|
|
# Exit: 0 on valid, 1 on validation failure
|
|
mrp_validate_id()
|
|
{
|
|
if [[ "${1}" =~ ^[A-Za-z]+[A-Za-z0-9._\-]+$ ]]; then
|
|
pr_dbg "ID \"%s\" is verified as valid" "${1}"
|
|
return 0
|
|
else
|
|
pr_err "The ID \"%s\" is invalid" "${1}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Validates platform ID used to identify releases
|
|
#
|
|
# Args: $1 platform ID
|
|
# Exit: 0 on valid, 1 on validation failure
|
|
mrp_validate_platform_id()
|
|
{
|
|
if [[ "${1}" =~ ^[a-z0-9_]+$ ]]; then
|
|
pr_dbg "Platform ID \"%s\" is verified as valid" "${1}"
|
|
return 0
|
|
else
|
|
pr_err "Platform ID \"%s\" is invalid" "${1}"
|
|
return 1
|
|
fi
|
|
|
|
return 0;
|
|
}
|
|
|
|
# Args: $1 ID of an extension
|
|
mrp_has_extension()
|
|
{
|
|
if [[ -f "${RPT_EXTS_DIR}/${1}/${1}.json" ]]; then
|
|
return 0;
|
|
else
|
|
return 1;
|
|
fi
|
|
}
|
|
|
|
mrp_get_all_extensions()
|
|
{
|
|
rpt_list_directories "${RPT_EXTS_DIR}" $1
|
|
}
|
|
|
|
# Gets index file for an extension (if exists)
|
|
# The file path returned is guaranteed to be a valid index file
|
|
#
|
|
# Args: $1 ID of the extension | $2 silent mode to only return exit code and treat errors as debug [default=0]
|
|
# Return: file path
|
|
# Exit:
|
|
# 0 - success
|
|
# 1 - parameters passed are invalid
|
|
# 2 - file not found
|
|
# 3 - semantic validation failure (json struct, json semantic, etc)
|
|
mrp_get_existing_index_file()
|
|
{
|
|
pr_dbg "Loading existing index file for extension %s" "${1}"
|
|
|
|
if ! mrp_validate_id "${1}"; then
|
|
return 1
|
|
fi
|
|
|
|
local IDX_FILE="${RPT_EXTS_DIR}/${1}/${1}.json"
|
|
if [[ ! -r "${IDX_FILE}" ]]; then
|
|
if [[ "${2:-0}" -eq 1 ]]; then # bash is really fugly...
|
|
pr_dbg "Extension %s index file %s is not readable or does not exist - extension is probably not added" "${1}" "${IDX_FILE}"
|
|
else
|
|
pr_err "Extension %s index file %s is not readable or does not exist - extension is probably not added" "${1}" "${IDX_FILE}"
|
|
fi
|
|
return 2
|
|
fi
|
|
|
|
if ! mrp_validate_index_file "${IDX_FILE}" "${IDX_FILE}"; then
|
|
if [[ "${2:-0}" -eq 1 ]]; then # bash is really fugly...
|
|
pr_dbg "Extension %s index file %s is is not a valid index file" "${1}" "${IDX_FILE}"
|
|
else
|
|
pr_err "Extension %s index file %s is is not a valid index file" "${1}" "${IDX_FILE}"
|
|
fi
|
|
return 3
|
|
fi
|
|
|
|
pr_dbg "Found valid existing index for %s extension at %s" "${1}" "${IDX_FILE}"
|
|
echo "${IDX_FILE}"
|
|
return 0
|
|
}
|
|
|
|
# Args: $1 extension id
|
|
mrp_show_ext_info()
|
|
{
|
|
local index_file
|
|
local index_file_exit
|
|
local -A info_kv
|
|
index_file=$(mrp_get_existing_index_file "${1}" 1)
|
|
index_file_exit=$?
|
|
|
|
pr_info "========================================== %s ==========================================" "${1}"
|
|
case $index_file_exit in
|
|
0) brp_read_kv_to_array "${index_file}" 'info' info_kv
|
|
pr_info "Extension name: %s" "${info_kv[name]}"
|
|
if [[ ! -z ${info_kv[description]+x} ]]; then
|
|
pr_info "Description: %s" "${info_kv[description]}"
|
|
else
|
|
pr_dbg "Description: <not provided>"
|
|
fi
|
|
pr_info "To get help visit: %s" "${info_kv[help_url]}"
|
|
if [[ ! -z ${info_kv[packer_url]+x} ]]; then
|
|
pr_info "Extension preparer/packer: %s" "${info_kv[packer_url]}"
|
|
else
|
|
pr_dbg "Extension preparer/packer: <not provided>"
|
|
fi
|
|
if [[ ! -z ${info_kv[author_url]+x} ]]; then
|
|
pr_info "Software author: %s" "${info_kv[author_url]}"
|
|
else
|
|
pr_dbg "Software author: <not provided>"
|
|
fi
|
|
pr_info "Update URL: %s" "$(brp_json_get_field "${index_file}" 'url' 1)"
|
|
|
|
brp_read_kv_to_array "${index_file}" 'releases' info_kv
|
|
local platforms=''
|
|
for platform in "${!info_kv[@]}"; do
|
|
platforms+="${platform} "
|
|
done
|
|
|
|
pr_info "Platforms supported: %s" "${platforms}"
|
|
|
|
;;
|
|
1) pr_err "Extension ID %s is invalid" "${1}"
|
|
;;
|
|
2) pr_err "Extension %s is not installed" "${1}"
|
|
;;
|
|
3) pr_err "Extension %s index is invalid - try \"%s update\" to fix it" "${1}" "${MRP_SRC_NAME}"
|
|
;;
|
|
*) pr_err "Unknown error %d" "${index_file_exit}"
|
|
esac
|
|
pr_info "=======================================================================================\n"
|
|
}
|
|
|
|
# Returns standardized error of extension index validation failure
|
|
#
|
|
# Args: $1 extension index URL | $2 id of the extension (if known) | $2 error message
|
|
mrp_validate_ext_idx_fail()
|
|
{
|
|
pr_err "Extension loaded from %s (id: %s) is invalid: %s. Please report that to the extension maintainer via help URL" \
|
|
"${1}" "${2}" "${3}"
|
|
}
|
|
|
|
# Validates extension index file
|
|
#
|
|
# Args:
|
|
# $1 Path to the index file
|
|
# $2 URL or path of the index file (if known)
|
|
# $3 Verify entries [validate all URLs and post warnings if they're not valid, returning 2 if any are invalid]
|
|
# Exit: 0 - success; 1 - failure; 2 - soft-failure
|
|
mrp_validate_index_file()
|
|
{
|
|
pr_dbg "Validating extension index file \"%s\"" "${1}"
|
|
|
|
if ! brp_json_validate "${1}" 1; then # validate JSON *file*, not its format/semantic - it will be parsable
|
|
mrp_validate_ext_idx_fail "${2}" '' 'index JSON file is unparsable'
|
|
return 1
|
|
fi
|
|
|
|
local id=$(brp_json_get_field "${1}" 'id') # this will error-out if field doesn't exist at all
|
|
if ! mrp_validate_id "${id}"; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" 'the ID did not pass validation'
|
|
return 1
|
|
fi
|
|
|
|
# todo validate URL optionally?
|
|
if [[ "$(brp_json_has_field "${1}" 'url')" -ne '1' ]]; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" 'index has no update URL'
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$(brp_json_has_field "${1}" 'info')" -ne '1' ]]; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" 'index has no info section'
|
|
return 1
|
|
fi
|
|
|
|
local -A info_kv
|
|
brp_read_kv_to_array "${1}" 'info' info_kv
|
|
if [[ -z "${info_kv[name]+x}" ]] || [[ "${info_kv[name]}" == '' ]]; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" 'index info section has no/empty name defined'
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "${info_kv[help_url]+x}" ]] || [[ "${info_kv[help_url]}" == '' ]]; then
|
|
mrp_validate_ext_idx_fail "${1}" "${id}" 'index info section has no/empty help_url defined'
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$(brp_json_has_field "${1}" 'releases')" -ne '1' ]]; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" 'index has no releases section'
|
|
return 1
|
|
fi
|
|
|
|
local -a releases
|
|
brp_json_get_keys "${1}" 'releases' releases
|
|
for rel_id in "${releases[@]}"; do
|
|
if ! mrp_validate_platform_id "${rel_id}"; then
|
|
mrp_validate_ext_idx_fail "${2}" "${id}" "release ID \"${rel_id}\" is invalid"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
pr_dbg "Extension index file \"%s\" OK" "${1}"
|
|
|
|
return 0
|
|
}
|
|
|
|
# Returns standardized error of extension recipe validation failure
|
|
#
|
|
# Args: $1 extension recipe URL | $2 id of the extension (if known) | $3 platform id | $4 error message
|
|
mrp_validate_ext_recipe_fail()
|
|
{
|
|
local ext_id;
|
|
if [[ "${2}" == '' ]]; then
|
|
ext_id='<unknown>'
|
|
else
|
|
ext_id="${2}"
|
|
fi
|
|
|
|
|
|
pr_err "Extension (id: %s) recipe for %s loaded from %s is invalid: %s. Please report that to the extension maintainer via help URL" \
|
|
"${2}" "${3}" "${1}" "${4}"
|
|
}
|
|
|
|
# Validates extension recipe file
|
|
#
|
|
# Args:
|
|
# $1 extension ID
|
|
# $2 platform ID
|
|
# $3 Path to the recipe file
|
|
# $x [removed?] Verify URLs [validate all URLs and post warnings if they're not valid, returning 2 if any are invalid]
|
|
# Exit: 0 - success; 1 - failure; 2 - soft-failure of URLs
|
|
mrp_validate_recipe_file()
|
|
{
|
|
pr_dbg "Validating extension index file \"%s\"" "${1}"
|
|
|
|
if ! brp_json_validate "${3}" 1; then # validate JSON *file*, not its format/semantic - it will be parsable
|
|
mrp_validate_ext_recipe_fail "${3}" "${1}" "${2}" 'recipe JSON file is unparsable'
|
|
return 1
|
|
fi
|
|
|
|
|
|
if [[ "$(brp_json_has_field "${3}" 'files')" -ne '1' ]]; then
|
|
mrp_validate_ext_recipe_fail "${3}" "${1}" "${2}" 'recipe file lacks files section'
|
|
return 1
|
|
fi
|
|
|
|
# we're not verifying the structure of files here as during the update it will do that attempting to download them
|
|
|
|
# todo: this should check if sections aren't empty but this is annoying in bash
|
|
if [[ "$(brp_json_has_field "${3}" 'kmods')" -ne '1' ]] && [[ "$(brp_json_has_field "${3}" 'scripts')" -ne '1' ]]; then
|
|
mrp_validate_ext_recipe_fail "${3}" "${1}" "${2}" 'recipe file does not define kmods nor scripts'
|
|
return 1
|
|
fi
|
|
|
|
local -A scripts_kv
|
|
brp_read_kv_to_array "${3}" "scripts" scripts_kv # we don't care about the order read here
|
|
for scr_name in "${!scripts_kv[@]}"; do
|
|
case "${scr_name}" in
|
|
on_boot)
|
|
;;
|
|
on_os_load)
|
|
;;
|
|
check_kmod)
|
|
if [[ "$(brp_json_has_field "${3}" 'kmods')" -ne '1' ]]; then
|
|
mrp_validate_ext_recipe_fail "${3}" "${1}" "${2}" 'recipe contains check_kmod script without any kmods defined'
|
|
return 1
|
|
fi
|
|
;;
|
|
*) pr_warn "Extension (id: %s) recipe for %s loaded from %s looks suspicious. It defines unknown script type %s" \
|
|
"${1}" "${2}" "${3}" "${scr_name}"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
# Args: $1 URL
|
|
# Return: path to a temp file on exit=0
|
|
# Exit: 0 on exit, any other positive number indicates error
|
|
mrp_fetch_new_ext_index()
|
|
{
|
|
|
|
readonly URL="${1}"
|
|
local MRP_TMP_IDX="${RPT_EXTS_DIR}/_new_ext_index.tmp_json"
|
|
rm "${MRP_TMP_IDX}" &> /dev/null
|
|
|
|
if [ ${URL::1} == "#" ]; then
|
|
pr_warn "Index file copied locally from %s to %s" "${URL}" "${MRP_TMP_IDX}"
|
|
brp_cp_flat "${URL:1}" "${MRP_TMP_IDX}"
|
|
else
|
|
pr_dbg "Index is remote - getting from %s to %s" "${URL}" "${MRP_TMP_IDX}"
|
|
rpt_download_remote "${URL}" "${MRP_TMP_IDX}" 1
|
|
fi
|
|
|
|
echo "${MRP_TMP_IDX}"
|
|
}
|
|
|
|
# Args:
|
|
# $1 ID of the extension
|
|
# $2 platform code
|
|
# Exit:
|
|
# 0: success
|
|
# 1: error occurred (message will be printed)
|
|
mrp_fetch_new_ext_recipe()
|
|
{
|
|
pr_dbg "Fetching new recipe for extension %s and platform %s" "${1}" "${2}"
|
|
|
|
if ! mrp_validate_platform_id "${2}"; then # extension ID will be verified by mrp_get_existing_index_file
|
|
pr_err "Platform ID %s is not valid" "${2}"
|
|
return 1
|
|
fi
|
|
|
|
local index_file;
|
|
index_file=$(mrp_get_existing_index_file "${1}")
|
|
if [ $? -ne 0 ]; then
|
|
pr_err "Failed to load index file for extension %s - see errors above for details" "${1}"
|
|
return 1
|
|
fi
|
|
|
|
local recipe_url;
|
|
recipe_url=$(brp_json_get_field "${index_file}" "releases.${2}" 1)
|
|
if [[ $? -ne 0 ]] || [[ "${recipe_url}" == 'null' ]]; then
|
|
pr_err "The extension %s was found. However, the extension index has no recipe for %s platform. It may not be" "${1}" "${2}"
|
|
pr_err "supported on that platform, or author didn't updated it for that platform yet. You can try running"
|
|
pr_err "\"%s update\" to refresh indexes for all extensions manually. Below are the currently known information about" "${MRP_SRC_NAME}"
|
|
pr_err "the extension stored locally:"
|
|
mrp_show_ext_info "${1}"
|
|
return 1
|
|
fi
|
|
|
|
local mrp_tmp_rcp="${RPT_EXTS_DIR}/_ext_new_rcp.tmp_json"
|
|
rm "${mrp_tmp_rcp}" &> /dev/null
|
|
|
|
rpt_download_remote "${recipe_url}" "${mrp_tmp_rcp}" 1
|
|
brp_json_validate "${mrp_tmp_rcp}" # validate JSON *file*, not its format/semantic
|
|
|
|
echo "${mrp_tmp_rcp}"
|
|
}
|
|
|
|
# Gets recipe file for an extension (if exists)
|
|
# The file path returned is guaranteed to be a valid recipe file
|
|
#
|
|
# Args:
|
|
# $1 ID of the extension
|
|
# $2 Platform code
|
|
# Return: file path (if exit=0)
|
|
# Exit:
|
|
# 0 - success
|
|
# 1 - invalid values passed (syntax error)
|
|
# 2 - recipe not found
|
|
# 3 - recipe semantic validation failure (id, json struct, json semantic, etc)
|
|
mrp_get_existing_recipe_file_path()
|
|
{
|
|
if ! mrp_validate_id "${1}"; then
|
|
return 1
|
|
fi
|
|
|
|
local RCP_FILE="${RPT_EXTS_DIR}/${1}/${2}/${2}.json"
|
|
if [ ! -r "${RCP_FILE}" ]; then
|
|
return 2
|
|
fi
|
|
|
|
if ! mrp_validate_recipe_file "${1}" "${2}" "${RCP_FILE}"; then
|
|
return 3
|
|
fi
|
|
|
|
echo "${RCP_FILE}"
|
|
return 0
|
|
}
|
|
|
|
# Args: $1 extension id [optional]
|
|
__action_info()
|
|
{
|
|
if [[ "$#" -gt 1 ]]; then
|
|
pr_crit "\"%s info\" expected 0 or 1 argument - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
if [[ "$#" -eq 1 ]]; then
|
|
mrp_show_ext_info "${1}"
|
|
return
|
|
fi
|
|
|
|
local -a extensions
|
|
mrp_get_all_extensions extensions
|
|
for ext_id in ${extensions[@]+"${extensions[@]}"}; do
|
|
mrp_show_ext_info "${ext_id}"
|
|
done
|
|
}
|
|
|
|
# Args: $1 URL to index
|
|
__action_add()
|
|
{
|
|
if [[ "$#" -ne 1 ]]; then
|
|
pr_crit "\"%s add\" expected 1 argument - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
pr_process "Adding new extension from %s" "${1}"
|
|
|
|
local tmp_idx_file;
|
|
tmp_idx_file=$(mrp_fetch_new_ext_index "${1}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to add \"%s\" as an extension:\n\n%s\n", "${1}" "${tmp_idx_file}"
|
|
fi
|
|
|
|
if ! mrp_validate_index_file "${tmp_idx_file}" "${1}"; then
|
|
pr_crit "The index file for %s extension is invalid - please report that to the extension maintainer" "${1}"
|
|
fi
|
|
|
|
ext_id=$(brp_json_get_field "${tmp_idx_file}" 'id')
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to get ID from extension index file downloaded from \"%s\":\n\n%s\n", "${1}" "${ext_id}"
|
|
fi
|
|
|
|
# before we even validate new file we need to check if a given extension exists maybe
|
|
local IDX_FILE="${RPT_EXTS_DIR}/${ext_id}/${ext_id}.json"
|
|
if [[ -e "${IDX_FILE}" ]]; then
|
|
pr_crit "Extension is already added (index exists at %s). For more info use \"%s info %s\"" \
|
|
"${IDX_FILE}" "${MRP_SRC_NAME}" "${ext_id}"
|
|
fi
|
|
|
|
local THIS_EXT_DIR="${RPT_EXTS_DIR}/${ext_id}"
|
|
if [[ -e "${THIS_EXT_DIR}" ]]; then
|
|
pr_crit "Extension %s is damaged. Its index does NOT exists at %s but its folder DOES at %s" \
|
|
"${ext_id}" "${IDX_FILE}" "${THIS_EXT_DIR}"
|
|
fi
|
|
|
|
brp_mkdir "${THIS_EXT_DIR}"
|
|
brp_cp_flat "${tmp_idx_file}" "${IDX_FILE}"
|
|
"${RM_PATH}" "${tmp_idx_file}" || pr_warn "Failed to remove temp file %s" "${tmp_idx_file}"
|
|
|
|
pr_process_ok
|
|
mrp_show_ext_info "${ext_id}"
|
|
}
|
|
|
|
# Args: $1 id of the extension
|
|
__action_remove()
|
|
{
|
|
if [[ "$#" -ne 1 ]]; then
|
|
pr_crit "\"%s remove\" expected 1 argument - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
local idx_file;
|
|
idx_file="$(mrp_get_existing_index_file "${1}")" # id will be validated here [to prevent touching random files]
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Extension cannot be removed due to previous errors"
|
|
fi
|
|
|
|
if ! "${RM_PATH}" -rf "${RPT_EXTS_DIR}/${1}"; then
|
|
pr_crit "Failed to remove %s extension directory" "${1}"
|
|
fi
|
|
|
|
pr_info "Extension %s has been removed" "${1}"
|
|
}
|
|
|
|
# Args: $1 extension ID | $2 URL to index
|
|
__action_force_add()
|
|
{
|
|
if [[ "$#" -ne 2 ]]; then
|
|
pr_crit "\"%s force_add\" expected 2 arguments - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
local index_file;
|
|
index_file=$(mrp_get_existing_index_file "${1}" 1)
|
|
local index_out=$?
|
|
|
|
## 0 - success
|
|
## 1 - parameters passed are invalid
|
|
## 2 - file not found
|
|
## 3 - semantic validation failure (json struct, json semantic, etc)
|
|
|
|
case $index_out in
|
|
0) # index was found & loaded correctly
|
|
pr_dbg "Extension %s is installed, checking URL" "${1}"
|
|
local index_url=$(brp_json_get_field "${index_file}" "url")
|
|
if [[ "${index_url}" != "${2}" ]]; then
|
|
pr_info "Reinstalling extension %s as its index location changed from %s to %s" "${1}" "${index_url}" "${2}"
|
|
__action_remove "${1}"
|
|
__action_add "${2}"
|
|
else
|
|
pr_info "Extension %s is already installed from %s" "${1}" "${index_url}"
|
|
fi
|
|
;;
|
|
|
|
1)
|
|
pr_crit "Extension ID \"%s\" is invalid - see above for details" "${1}"
|
|
;;
|
|
|
|
2) # not found/not installed
|
|
__action_add "${2}"
|
|
;;
|
|
|
|
3) # damaged
|
|
pr_warn "Extension %s is damaged - reinstalling from %s"
|
|
__action_remove "${1}"
|
|
__action_add "${2}"
|
|
;;
|
|
*)
|
|
pr_crit "Unknown error #%d occurred while loading extension %s index. Please report this as a bug." \
|
|
"${index_out}" "${1}"
|
|
esac
|
|
|
|
}
|
|
|
|
# Args: $1 list of extensions [optional, if not specified it will cleanup all]
|
|
__action_cleanup()
|
|
{
|
|
if [[ "$#" -gt 1 ]]; then
|
|
pr_crit "\"%s cleanup\" expected 0 or 1 argument - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
local -a extensions
|
|
if [[ -z "${1+0}" ]]; then # no extensions list passed - use all
|
|
pr_dbg "No extensions list passed - getting all"
|
|
mrp_get_all_extensions extensions
|
|
else # passed list of extensions - split them (we don't need to verify if they exist - we will try to read them anyway)
|
|
pr_dbg "Extensions list passed - splitting"
|
|
rpt_text_to_array ',' "${2}" extensions
|
|
fi
|
|
|
|
local failed=0
|
|
for ext_id in ${extensions[@]+"${extensions[@]}"}; do
|
|
pr_process "Removing all platform files for %s extension" "${ext_id}"
|
|
"${RM_PATH}" -rf "${RPT_EXTS_DIR}/${ext_id}/*" || pr_crit "Failed to cleanup extension %s" "${ext_id}"
|
|
pr_process_ok
|
|
done
|
|
}
|
|
|
|
# Called to error-out from recipe fill-in which failed
|
|
#
|
|
# Args: $1 platform dir to clean | $2 extension id | $3 platform id | $4 error
|
|
mrp_fill_recipe_fail()
|
|
{
|
|
pr_err "Recipe file for extension %s platform %s is logically invalid - %s. You SHOULD contact the extension packer to report that (see below)" \
|
|
"${2}" "${3}" "${4}"
|
|
mrp_show_ext_info "${ext_id}"
|
|
|
|
pr_dbg "Cleaning up %s" "${1}"
|
|
"${RM_PATH}" -rf "${1}"
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to delete %s after failed recipe fill attempt - please delete it manually"
|
|
fi
|
|
}
|
|
|
|
# Takes a new recipe, nukes old data for given ext+platform and downloads everything from the recipe
|
|
# It's assumed that the recipe passed here is semantically valid and matches the platform/extension. This function will
|
|
# always leave the directory for ext+platform in a valid state (or nuke it)
|
|
#
|
|
# Args: $1 extension id | $2 platform id | $3 path to recipe file to use [probably freshly downloaded]
|
|
mrp_fill_recipe()
|
|
{
|
|
local ext_id="${1}"
|
|
local platform_id="${2}"
|
|
local tmp_rcp_file="${3}"
|
|
local platform_rcp_file;
|
|
local platform_dir;
|
|
|
|
pr_info "Filling-in newly downloaded recipe for extension %s platform %s" "${ext_id}" "${platform_id}"
|
|
|
|
# prepare new directory for the extension+platform combo
|
|
platform_dir="${RPT_EXTS_DIR}/${ext_id}/${platform_id}"
|
|
pr_dbg "Platform dir for extension %s platform %s is %s" "${ext_id}" "${platform_id}" "${platform_dir}"
|
|
if [[ -d "${platform_dir}" ]]; then # we don't really care if the recipe is old or broken - if it's there nuke it
|
|
pr_dbg "Removing old platform dir %s" "${platform_dir}"
|
|
"${RM_PATH}" -rf "${RPT_EXTS_DIR}/${ext_id}/${platform_id}/"
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to delete %s while preparing to update extension %s for %s platform - try deleting it manually?" \
|
|
"${platform_dir}" "${ext_id}" "${platform_id}"
|
|
fi
|
|
fi
|
|
pr_dbg "Creating new platform dir %s" "${platform_dir}"
|
|
brp_mkdir "${platform_dir}"
|
|
platform_rcp_file="${platform_dir}/${platform_id}.json"
|
|
|
|
pr_dbg "Copying recipe %s to its permanent place in %s" "${tmp_rcp_file}" "${platform_rcp_file}"
|
|
brp_cp_flat "${tmp_rcp_file}" "${platform_rcp_file}"
|
|
|
|
local -a file_idxs;
|
|
local -A file_meta;
|
|
local platform_fpatch;
|
|
brp_json_get_keys "${platform_rcp_file}" 'files' file_idxs
|
|
for file_idx in "${file_idxs[@]}"; do
|
|
pr_dbg "Processing file entry #%d" "${file_idx}"
|
|
|
|
brp_read_kv_to_array "${platform_rcp_file}" "files[${file_idx}]" file_meta # todo: move that to recipe validation
|
|
for fm_key in name url sha256 packed; do #todo here also check the file name in recipe so there are no rogue chars
|
|
if [[ -z "${file_meta[${fm_key}]+0}" ]]; then
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "no [${fm_key}] key for file at idx #${file_idx}"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
platform_fpatch="${platform_dir}/${file_meta[name]}"
|
|
if [[ -e "${platform_fpatch}" ]]; then # this can happen if two file records define the same name OR previous packed archive had that file
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "file ${file_meta[name]} already exists while processing idx #${file_idx} (duplicated name?)"
|
|
return 1
|
|
fi
|
|
|
|
rpt_download_remote "${file_meta[url]}" "${platform_fpatch}" 0
|
|
if [[ $? -ne 0 ]]; then
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "failed to download file ${file_meta[url]}"
|
|
return 1
|
|
fi
|
|
|
|
brp_verify_file_sha256 "${platform_fpatch}" "${file_meta[sha256]}" 1
|
|
if [[ $? -ne 0 ]]; then
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "failed to verify file ${file_meta[url]}"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "${file_meta[packed]}" == 'true' ]]; then
|
|
pr_dbg "File %s is marked as a packed archive - unpacking" "${platform_fpatch}"
|
|
brp_unpack_tar_flat "${platform_fpatch}" "${platform_dir}/" 0
|
|
if [ $? -ne 0 ]; then
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "file download ${file_meta[url]} cannot be unpacked"
|
|
return 1
|
|
fi
|
|
# this is critical as we don't want the archive accidentally landing in the final image
|
|
"${RM_PATH}" "${platform_fpatch}" || pr_crit "Failed to delete archive %s"
|
|
fi
|
|
done
|
|
|
|
# at this point we've got all files - now we need to check that all kernel modules & scripts defined are actually there
|
|
local -A files_kv;
|
|
if [[ "$(brp_json_has_field "${platform_rcp_file}" 'kmods')" -eq 1 ]]; then # not all extensions must have *.ko
|
|
pr_dbg "Extension has kernel modules - checking"
|
|
brp_read_kv_to_array "${platform_rcp_file}" "kmods" files_kv
|
|
for ko_name in "${!files_kv[@]}"; do
|
|
platform_fpatch="${platform_dir}/${ko_name}"
|
|
pr_dbg "Checking if file exists at %s" "${platform_fpatch}"
|
|
|
|
if [[ ! -f "${platform_fpatch}" ]]; then # it HAS TO BE a normal file, it's deliberate here
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "recipe defines kmod ${ko_name} *FILE* which doesn't exist after all files entries are processed"
|
|
return 1
|
|
fi
|
|
done
|
|
fi
|
|
if [[ "$(brp_json_has_field "${platform_rcp_file}" 'scripts')" -eq 1 ]]; then # not all extensions must have scripts
|
|
pr_dbg "Extension has scripts - checking"
|
|
brp_read_kv_to_array "${platform_rcp_file}" "scripts" files_kv
|
|
for script_action in "${!files_kv[@]}"; do
|
|
platform_fpatch="${platform_dir}/${files_kv[$script_action]}"
|
|
pr_dbg "Checking if file for action %s exists at %s" "${script_action}" "${platform_fpatch}"
|
|
|
|
if [[ ! -f "${platform_fpatch}" ]]; then # it HAS TO BE a normal file, it's deliberate here
|
|
mrp_fill_recipe_fail "${platform_dir}" "${ext_id}" "${platform_id}" "recipe defines ${files_kv[$script_action]} *FILE* for ${script_action} script action which doesn't exist after all files entries are processed"
|
|
return 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
pr_info "Successfully processed recipe for extension %s platform %s" "${ext_id}" "${platform_id}"
|
|
}
|
|
|
|
# Args: $1 list of extensions [optional, if not specified it will update all]
|
|
__action_update()
|
|
{
|
|
if [[ "$#" -gt 1 ]]; then
|
|
pr_crit "\"%s update\" expected 0 or 1 argument - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
local -a extensions
|
|
if [[ -z "${1+0}" ]]; then # no extensions list passed - use all
|
|
pr_dbg "No extensions list passed - getting all"
|
|
mrp_get_all_extensions extensions
|
|
else # passed list of extensions - split them (we don't need to verify if they exist - we will try to read them anyway)
|
|
pr_dbg "Extensions list passed - splitting"
|
|
rpt_text_to_array ',' "${1}" extensions
|
|
fi
|
|
|
|
local index_url
|
|
local cur_index_file
|
|
local cur_index_sha256
|
|
local new_index_file
|
|
local new_index_sha256
|
|
local failed=0
|
|
for ext_id in ${extensions[@]+"${extensions[@]}"}; do
|
|
pr_process "Updating %s extension" "${ext_id}"
|
|
cur_index_file=$(mrp_get_existing_index_file "${ext_id}")
|
|
if [ $? -ne 0 ]; then
|
|
pr_err "Failed to load index file for extension %s - see errors above for details" "${ext_id}"
|
|
return 1
|
|
fi
|
|
|
|
index_url=$(brp_json_get_field "${cur_index_file}" 'url')
|
|
new_index_file=$(mrp_fetch_new_ext_index "${index_url}")
|
|
if [[ $? -ne 0 ]]; then # so we cannot get new index
|
|
pr_err "Failed to download index file for %s extension from %s" "${ext_id}" "${index_url}"
|
|
((failed=failed+1))
|
|
continue
|
|
fi
|
|
|
|
# now we know we have the new [valid] recipe file (since previous if allowed us to get here)
|
|
pr_dbg "Got new index for %s from %s to %s" "${ext_id}" "${index_url}" "${new_index_file}"
|
|
|
|
cur_index_sha256=$(rpt_get_file_sha256 "${cur_index_file}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to hash old index file %s for comparison:\n\n%s" "${cur_index_file}" "${cur_index_sha256}"
|
|
fi
|
|
|
|
new_index_sha256=$(rpt_get_file_sha256 "${new_index_file}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to hash new index file %s for comparison:\n\n%s" "${new_index_file}" "${new_index_sha256}"
|
|
fi
|
|
|
|
pr_dbg "Current idx SHA256=%s vs new SHA256=%s" "${cur_index_sha256}" "${new_index_sha256}"
|
|
if [[ "${cur_index_sha256}" == "${new_index_sha256}" ]]; then
|
|
pr_info "Extension %s index is already up to date" "${ext_id}"
|
|
"${RM_PATH}" "${new_index_file}" || pr_warn "Failed to remove temp file %s" "${new_index_file}"
|
|
continue
|
|
fi
|
|
|
|
# todo: for now we can invalidate all platforms but properly we shouldn't invalidate if the recipe URLs are the same
|
|
# However, this is tricky as we need to compare list of platforms as well... it's VERY ANNOYING to do it in bash
|
|
"${RM_PATH}" -rf "${RPT_EXTS_DIR}/${ext_id}/*/"
|
|
"${MV_PATH}" "${new_index_file}" "${cur_index_file}" || pr_crit "Failed to install new index to %s" "${cur_index_file}"
|
|
done
|
|
|
|
if [[ "${failed}" -eq 0 ]]; then
|
|
pr_process_ok
|
|
else
|
|
pr_err "%d extensions failed to update" "${failed}"
|
|
fi
|
|
}
|
|
|
|
# Args: $1 platform id | $2 extensions ID list [optional]
|
|
__action__update_platform_exts()
|
|
{
|
|
if [[ "$#" -lt 1 ]] || [[ "$#" -gt 2 ]]; then
|
|
pr_crit "\"%s _update_platform_exts\" expected 1-2 arguments - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
pr_process "Updating %s platforms extensions" "${1}"
|
|
|
|
local platform_id="${1}"
|
|
if ! mrp_validate_platform_id "${platform_id}"; then
|
|
pr_err "Platform ID %s is not valid" "${platform_id}"
|
|
return 1
|
|
fi
|
|
|
|
local -a extensions
|
|
if [[ -z "${2+0}" ]]; then # no extensions list passed - use all
|
|
pr_dbg "No extensions list passed - getting all"
|
|
mrp_get_all_extensions extensions
|
|
else # passed list of extensions - split them (we don't need to verify if they exist - we will try to read them anyway)
|
|
pr_dbg "Extensions list passed - splitting"
|
|
rpt_text_to_array ',' "${2}" extensions
|
|
fi
|
|
|
|
|
|
local cur_recipe_file;
|
|
local cur_recipe_sha256;
|
|
local cur_recipe_result;
|
|
local new_recipe_file;
|
|
local new_recipe_sha256;
|
|
local platform_dir;
|
|
local hard_fail=0;
|
|
for ext_id in ${extensions[@]+"${extensions[@]}"}; do
|
|
pr_dbg "Processing extension %s for %s platform" "${ext_id}" "${platform_id}"
|
|
if ! mrp_has_extension "${ext_id}"; then
|
|
pr_crit "Extension \"%s\" is not added/installed - did you misspell the name or forgot to do \"%s add <URL>\" first?" \
|
|
"${ext_id}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
cur_recipe_file=$(mrp_get_existing_recipe_file_path "${ext_id}" "${platform_id}")
|
|
cur_recipe_result=$?
|
|
if [[ "${cur_recipe_result}" -eq 1 ]]; then
|
|
pr_crit "<BUG> Failed to read current recipe failure due to call error" # this is some bug in validation
|
|
else
|
|
pr_dbg "Attempted to get existing recipe - call resulted in code #%d" "${cur_recipe_result}"
|
|
fi
|
|
|
|
#todo: check if ok & recently checked and skip over the whole checking below (to not re-download receipt all the time)
|
|
|
|
new_recipe_file=$(mrp_fetch_new_ext_recipe "${ext_id}" "${platform_id}")
|
|
if [[ $? -ne 0 ]]; then # so we cannot get the recipe
|
|
case "${cur_recipe_result}" in
|
|
0) pr_warn "Failed to update recipe for %s extension for platform %s. The script will try to continue with the old" "${ext_id}" "${platform_id}"
|
|
pr_warn "recipe. If the old recipe still works at worst you will miss on an update. Contact the packer of the"
|
|
pr_warn "extension if this problem persists (displayed below)"
|
|
hard_fail=0
|
|
;;
|
|
2) pr_err "Failed to update recipe for %s extension for platform %s. The script will terminate as you do not" "${ext_id}" "${platform_id}"
|
|
pr_err "have previously downloaded recipe which can be used if download fails. Try again later. If problem"
|
|
pr_err "persists contact the extension packer for support (displayed below)"
|
|
hard_fail=1
|
|
;;
|
|
3) pr_err "Failed to update recipe for %s extension for platform %s. The script will terminate as your existing" "${ext_id}" "${platform_id}"
|
|
pr_err "recipe is damaged and cannot be used if download fails. Try again later. If problem persists"
|
|
pr_err "contact the extension packer for support (displayed below)"
|
|
hard_fail=1
|
|
;;
|
|
*) pr_crit "Unhandled cur_recipe_result exception #%d" "${cur_recipe_result}"
|
|
;;
|
|
esac
|
|
|
|
mrp_show_ext_info "${ext_id}"
|
|
if [[ "${hard_fail}" -eq 1 ]]; then
|
|
pr_crit "Cannot continue due to previous errors (see above)"
|
|
fi
|
|
|
|
continue # if there's no new recipe we cannot download any files or anything - we assume offline operation
|
|
fi
|
|
|
|
# now we know we have the new [valid] recipe file (since previous if allowed us to get here)
|
|
pr_dbg "Got new recipe to %s" "${new_recipe_file}"
|
|
|
|
if [[ "${cur_recipe_result}" -eq 0 ]]; then # we have the current one so we can try to check if it's the same
|
|
pr_dbg "Both new (%s) and old (%s) recipes exist - comparing" "${new_recipe_file}" "${cur_recipe_file}"
|
|
|
|
cur_recipe_sha256=$(rpt_get_file_sha256 "${cur_recipe_file}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to hash old recipe file %s for comparison:\n\n%s" "${cur_recipe_file}" "${cur_recipe_sha256}"
|
|
fi
|
|
|
|
new_recipe_sha256=$(rpt_get_file_sha256 "${new_recipe_file}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to hash new recipe file %s for comparison:\n\n%s" "${new_recipe_file}" "${new_recipe_sha256}"
|
|
fi
|
|
|
|
if [[ "${cur_recipe_sha256}" == "${new_recipe_sha256}" ]]; then
|
|
pr_info "Extension %s for %s platform is already up to date" "${ext_id}" "${platform_id}"
|
|
"${RM_PATH}" "${new_recipe_file}" || pr_warn "Failed to remove temp file %s" "${new_recipe_file}"
|
|
continue
|
|
fi
|
|
|
|
fi
|
|
|
|
pr_dbg "Previous recipe is not usable (outdated, broken, or missing) - processing newly downloaded one"
|
|
# now we know know that either ext is out of date or something is wrong with the current recipe (see previous if)
|
|
# either way we need to cleanup old one and simply get new one
|
|
# but just before we do that let's verify new recipe - if there's a new one and we confirmed it's different (or the
|
|
# old one is not found/broken) it should explode and user should not be able to complete update
|
|
if ! mrp_validate_recipe_file "${ext_id}" "${platform_id}" "${new_recipe_file}"; then
|
|
pr_err "Failed to update recipe for %s extension for platform %s. The script will terminate as the new recipe is" "${ext_id}"
|
|
pr_err "available but it's invalid. Try again later. If problem persists contact the extension packer for support"
|
|
pr_err "(displayed below)"
|
|
mrp_show_ext_info "${ext_id}"
|
|
pr_crit "Cannot continue due to previous errors (see above)"
|
|
fi
|
|
|
|
mrp_fill_recipe "${ext_id}" "${platform_id}" "${new_recipe_file}"
|
|
"${RM_PATH}" "${new_recipe_file}" || pr_warn "Failed to remove temp file %s" "${new_recipe_file}"
|
|
|
|
done
|
|
|
|
pr_process_ok
|
|
}
|
|
|
|
__action__dump_exts()
|
|
{
|
|
if [[ "$#" -lt 2 ]] || [[ "$#" -gt 3 ]]; then
|
|
pr_crit "\"%s _dump\" expected 2-3 arguments - got %d. See \"%s help\" for details" "${MRP_SRC_NAME}" "${#}" "${MRP_SRC_NAME}"
|
|
fi
|
|
|
|
local platform_id="${1}"
|
|
local dump_dir="${2}"
|
|
pr_process "Dumping %s platform extensions to %s" "${platform_id}" "${dump_dir}"
|
|
|
|
if ! mrp_validate_platform_id "${platform_id}"; then
|
|
pr_err "Platform ID %s is not valid" "${platform_id}"
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -d "${dump_dir}" ] || [[ ! -z "$(${LS_PATH} -A "${dump_dir}")" ]]; then
|
|
pr_err "%s is not an **existing and empty** directory" "${dump_dir}"
|
|
return 1
|
|
fi
|
|
|
|
local -a extensions
|
|
if [[ -z "${3+0}" ]]; then # no extensions list passed - use all
|
|
pr_dbg "No extensions list passed - getting all"
|
|
mrp_get_all_extensions extensions
|
|
else # passed list of extensions - split them (we don't need to verify if they exist - we will try to read them anyway)
|
|
pr_dbg "Extensions list passed - splitting"
|
|
rpt_text_to_array ',' "${3}" extensions
|
|
fi
|
|
|
|
local platform_dir;
|
|
local dump_ext_di;
|
|
local platform_rcp_file;
|
|
local target_extensions; # list of extensions (space-separated) in order of how they should be loaded by the loader
|
|
local -A target_vars; # dump of variables for the script dumped to the final image to load everything in order
|
|
local -a files_keys;
|
|
local -A files_kv;
|
|
local ext_counter=-1;
|
|
local kmod_counter;
|
|
for ext_id in ${extensions[@]+"${extensions[@]}"}; do
|
|
((ext_counter++))
|
|
platform_dir="${RPT_EXTS_DIR}/${ext_id}/${platform_id}"
|
|
dump_ext_di="${dump_dir}/${ext_id}"
|
|
pr_dbg "Dumping platform %s extension %s from %s to %s" "${platform_id}" "${ext_id}" "${platform_dir}" "${dump_ext_di}"
|
|
|
|
platform_rcp_file=$(mrp_get_existing_recipe_file_path "${ext_id}" "${platform_id}")
|
|
if [[ $? -ne 0 ]]; then
|
|
pr_crit "Failed to dump extension %s for platform %s as its recipe file cannot be retrieved. Isn't the extension misspelled or not supported on that platform?" \
|
|
"${ext_id}" "${platform_id}"
|
|
fi
|
|
|
|
brp_cp_flat "${platform_dir}" "${dump_ext_di}" # theoretically this will suffice, but we can cleanup a bit
|
|
"${RM_PATH}" "${dump_ext_di}/${platform_id}.json" || true #this may safely fail (it shouldn't thou)
|
|
"${FIND_PATH}" "${dump_ext_di}" -type d -empty -delete # delete all empty dirs which may resulted from unpacking
|
|
|
|
# Handle kernel extensions (if any)
|
|
target_extensions+="${ext_id} " # POSIX shells don't care about leading/trailing whitespaces in IFS
|
|
if [[ "$(brp_json_has_field "${platform_rcp_file}" 'kmods')" -eq 1 ]]; then # not all extensions must have *.ko
|
|
pr_dbg "Extension has kernel modules - dumping"
|
|
brp_read_ordered_kv "${platform_rcp_file}" "kmods" files_keys files_kv
|
|
kmod_counter=0
|
|
for ko_name in ${files_keys[@]+"${files_keys[@]}"}; do
|
|
pr_dbg "Adding %s kmod (args: %s) from %s extension" "${ko_name}" "${files_kv[${ko_name}]}" "${ext_id}"
|
|
target_vars["EXT_${ext_counter}_kmod_files"]+="${ko_name} "
|
|
if [[ ! -z "${files_kv[${ko_name}]}" ]]; then
|
|
target_vars["EXT_${ext_counter}_kmod_${kmod_counter}_args"]="${files_kv[${ko_name}]}"
|
|
fi
|
|
((kmod_counter++))
|
|
done
|
|
fi
|
|
|
|
# Handle scripts (if any)
|
|
if [[ "$(brp_json_has_field "${platform_rcp_file}" 'scripts')" -eq 1 ]]; then # not all extensions must have scripts
|
|
pr_dbg "Extension has scripts - dumping"
|
|
brp_read_kv_to_array "${platform_rcp_file}" "scripts" files_kv # we don't care about the order read here
|
|
for script_action in "${!files_kv[@]}"; do
|
|
pr_dbg "Adding %s script for action %s from %s extension" \
|
|
"${script_action}" "${files_kv[${script_action}]}" "${ext_id}"
|
|
|
|
target_vars["EXT_${ext_counter}_scripts_${script_action}"]="${files_kv[${script_action}]}"
|
|
done
|
|
fi
|
|
done
|
|
|
|
# Copy bootstrap files
|
|
local target_exec_scr_path="${dump_dir}/exec.sh"
|
|
brp_cp_flat "include/loader-ext/readme.txt_" "${dump_dir}/__README__.txt"
|
|
brp_cp_flat "include/loader-ext/target_exec.sh_" "${target_exec_scr_path}"
|
|
rpt_make_executable "${target_exec_scr_path}"
|
|
|
|
# Fill-in bootstrap script
|
|
local ext_data='';
|
|
brp_replace_token_with_text "${target_exec_scr_path}" '@@@PLATFORM_ID@@@' "PLATFORM_ID=\"${platform_id}\""
|
|
brp_replace_token_with_text "${target_exec_scr_path}" '@@@EXTENSION_IDS@@@' "EXTENSION_IDS=\"${target_extensions}\""
|
|
for var_name in "${!target_vars[@]}"; do
|
|
ext_data+="${var_name}=\"${target_vars[${var_name}]}\""$'\n'
|
|
done
|
|
pr_dbg "Prepared EXT_DATA:\n%s" "${ext_data}"
|
|
brp_replace_token_with_text "${target_exec_scr_path}" '@@@EXT_DATA@@@' "${ext_data}"
|
|
|
|
}
|
|
|
|
__action_help ()
|
|
{
|
|
echo " RedPill Extensions Manager "
|
|
echo "=============================="
|
|
echo "Usage: ${MRP_SRC_NAME} <action> [arguments/options]"
|
|
echo "------------------------------"
|
|
echo "Actions intended for users:"
|
|
echo " info"
|
|
echo " Purpose: Gets information about an extension (or all of them)"
|
|
echo " Arguments:"
|
|
echo " [EXT_ID]: id of the extension; optional (if not specified it will list all)"
|
|
echo " Examples:"
|
|
echo " ${MRP_SRC_NAME} info # gets info about all installed"
|
|
echo " ${MRP_SRC_NAME} info thethorgroup.virtio # gets info about thethorgroup.virtio"
|
|
echo ""
|
|
echo " add"
|
|
echo " Purpose: Adds new extension. If exists this action will fail."
|
|
echo " Arguments:"
|
|
echo " URL: the url to an index file; argument is mandatory"
|
|
echo " Example: ${MRP_SRC_NAME} add https://example.tld/sample-ext/rpext-index.json"
|
|
echo ""
|
|
echo " force_add"
|
|
echo " Purpose: Adds new extension. If it exists url is verified to be the same, if not extension is removed"
|
|
echo " and reinstalled from the URL provided. If extension exists with the same URL nothing happens."
|
|
echo " Arguments:"
|
|
echo " EXT_ID: ID of the extension; argument is mandatory"
|
|
echo " URL: the url to an index file; argument is mandatory"
|
|
echo " Example: ${MRP_SRC_NAME} force_add example-dev.sample-ext https://example.tld/sample-ext/rpext-index.json"
|
|
echo ""
|
|
echo " cleanup"
|
|
echo " Purpose: Remove all platform (cache) files for an extension. If it does not exists this action will fail."
|
|
echo " Arguments:"
|
|
echo " [EXT_IDS]: comma-separated ordered list of extensions to cleanup; optional"
|
|
echo " Examples:"
|
|
echo " ${MRP_SRC_NAME} cleanup thethorgroup.virtio,thethorgroup.boot-wait # cleanup only 2 extensions listed"
|
|
echo " ${MRP_SRC_NAME} cleanup # cleanup all extensions"
|
|
echo ""
|
|
echo " remove"
|
|
echo " Purpose: Remove an extension and all its platform files. If it does not exists this action will fail."
|
|
echo " Arguments:"
|
|
echo " EXT_ID: if of the extension to remove; argument is mandatory"
|
|
echo " Example: ${MRP_SRC_NAME} remove badcoder.unstable-ext"
|
|
echo ""
|
|
echo " update"
|
|
echo " Purpose: Updates information about extensions; this will NOT download platform extensions itself"
|
|
echo " Arguments:"
|
|
echo " [EXT_IDS]: comma-separated ordered list of extensions to update; optional"
|
|
echo " Examples:"
|
|
echo " ${MRP_SRC_NAME} update thethorgroup.virtio,thethorgroup.boot-wait # update only 2 extensions listed"
|
|
echo " ${MRP_SRC_NAME} update # update all extensions installed"
|
|
echo ""
|
|
echo " help"
|
|
echo " Purpose: Helping you! (you're reading it right now)"
|
|
echo " Arguments: takes no arguments"
|
|
echo ""
|
|
echo "------------------------------"
|
|
echo "Actions intended for usage in scripts:"
|
|
echo " _update_platform_exts"
|
|
echo " Purpose: Checks all extensions added expecting the platform to be supported; updates all recipes & files"
|
|
echo " Arguments:"
|
|
echo " PLATFORM_CODE: id of the platform, e.g. ds3615xs_25556"
|
|
echo " [EXT_IDS]: comma-separated ordered list of extensions to include; optional"
|
|
echo ""
|
|
echo " _dump_exts"
|
|
echo " Purpose: Dump all extensions, their scripts + loader script; used by the redpill-load during image build"
|
|
echo " Arguments:"
|
|
echo " PLATFORM_CODE: id of the platform, e.g. ds3615xs_25556; required"
|
|
echo " DST_DIR: where to save all files; required"
|
|
echo " [EXT_IDS]: comma-separated ordered list of extensions to include; optional"
|
|
exit 1
|
|
}
|
|
|
|
# Checks if the extensions directory exists and creates an empty one if it doesn't so other things don't break
|
|
__housekeep_init()
|
|
{
|
|
if [[ -d "${RPT_EXTS_DIR}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
pr_warn "Your extensions directory %s doesn't exists - creating" "${RPT_EXTS_DIR}"
|
|
brp_mkdir "${RPT_EXTS_DIR}"
|
|
}
|
|
|
|
|
|
readonly ACTION_NAME=${1:-"help"}
|
|
case "${ACTION_NAME}" in
|
|
"" | "-h" | "--help")
|
|
__action_help
|
|
;;
|
|
*)
|
|
shift
|
|
__housekeep_init
|
|
__action_"${ACTION_NAME}" "$@"
|
|
if [ $? = 127 ]; then
|
|
echo "You've called \"${MRP_SRC_NAME} ${ACTION_NAME}\" - this action is unknown, see help below"
|
|
__action_help
|
|
fi
|
|
;;
|
|
esac
|