From 9bd59fca50f6241e23d92206ebf48e4cbef8a9bc Mon Sep 17 00:00:00 2001 From: Locutus73 Date: Thu, 30 May 2019 18:31:18 +0200 Subject: [PATCH] Version 0.9 - First commit, missing Updater config First commit, lacking any MiSTer Updater configuration capability. --- core_manager.sh | 436 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 core_manager.sh diff --git a/core_manager.sh b/core_manager.sh new file mode 100644 index 0000000..1b861f0 --- /dev/null +++ b/core_manager.sh @@ -0,0 +1,436 @@ +#!/bin/bash + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Copyright 2019 Alessandro "Locutus73" Miele + +# You can download the latest version of this script from: +# https://github.com/MiSTer-devel/Scripts_MiSTer + +# Version 0.9 - 2019-05-30 - First commit, lacking any MiSTer Updater configuration capability. + + + +# ========= OPTIONS ================== + +# ========= ADVANCED OPTIONS ========= +UPDATER_URL="https://github.com/MiSTer-devel/Updater_script_MiSTer/blob/master/mister_updater.sh" + +# ========= CODE STARTS HERE ========= + +function checkTERMINAL { +# if [ "$(uname -n)" != "MiSTer" ] +# then +# echo "This script must be run" +# echo "on a MiSTer system." +# exit 1 +# fi + if [[ ! (-t 0 && -t 1 && -t 2) ]] + then + echo "This script must be run" + echo "from an interactive terminal." + echo "Please press F9 (F12 to exit)" + echo "or use SSH." + exit 2 + fi +} + +function setupScriptINI { + # get the name of the script, or of the parent script if called through a 'curl ... | bash -' + ORIGINAL_SCRIPT_PATH="${0}" + [[ "${ORIGINAL_SCRIPT_PATH}" == "bash" ]] && \ + ORIGINAL_SCRIPT_PATH="$(ps -o comm,pid | awk -v PPID=${PPID} '$2 == PPID {print $1}')" + + setupCURL + TMP_INCLUDE_FILE=$(mktemp) + echo "Downloading ${UPDATER_URL/*\//}" + MISTER_UPDATER_CODE=$(${CURL} "${UPDATER_URL}?raw=true" | dos2unix) + [ "${MISTER_UPDATER_CODE}" == "" ] && echo "Error downloading ${UPDATER_URL/*\//}" && exit 1 + echo "${MISTER_UPDATER_CODE}" | \ + sed -n '/#========= USER OPTIONS =========/,/#========= CODE STARTS HERE =========/p' | \ + sed 's/#========= CODE STARTS HERE =========//' | \ + sed 's/declare -A/declare -g -A/g' | \ + sed 's/DOWNLOAD_NEW_CORES="true"/DOWNLOAD_NEW_CORES="false"/g' \ + > "${TMP_INCLUDE_FILE}" + source ${TMP_INCLUDE_FILE} + rm -f ${TMP_INCLUDE_FILE} + + # ini file can contain user defined variables (as bash commands) + # Load and execute the content of the ini file, if there is one + INI_PATH="$(dirname ${ORIGINAL_SCRIPT_PATH})/update.ini" + + if [ ! -f "${INI_PATH}" ] + then + echo "${MISTER_UPDATER_CODE}" | \ + sed -n '/#========= USER OPTIONS =========/,/#========= CODE STARTS HERE =========/p' | \ + sed 's/#========= CODE STARTS HERE =========//' | \ + sed 's/DOWNLOAD_NEW_CORES="true"/DOWNLOAD_NEW_CORES="false"/g' \ + > "${INI_PATH}" + fi + + echo "${MISTER_UPDATER_CODE}" | \ + sed -n '/^function checkCoreURL {/,/^}/p' \ + > "${TMP_INCLUDE_FILE}" + source ${TMP_INCLUDE_FILE} + rm -f ${TMP_INCLUDE_FILE} + + unset MISTER_UPDATER_CODE + + if [[ -f "${INI_PATH}" ]] ; then + # TMP_INCLUDE_FILE=$(mktemp) + # preventively eliminate DOS-specific format and exit command + dos2unix < "${INI_PATH}" 2> /dev/null | \ + grep -v "^exit" | \ + sed 's/declare -A/declare -g -A/g' \ + > ${TMP_INCLUDE_FILE} + source ${TMP_INCLUDE_FILE} + rm -f ${TMP_INCLUDE_FILE} + fi +} + +function setupCURL +{ + [ ! -z "${CURL}" ] && return + CURL_RETRY="--connect-timeout 15 --max-time 120 --retry 3 --retry-delay 5" + # test network and https by pinging the most available website + SSL_SECURITY_OPTION="" + curl ${CURL_RETRY} --silent https://google.com > /dev/null 2>&1 + case $? in + 0) + ;; + 60) + if [[ "${ALLOW_INSECURE_SSL}" == "true" ]] + then + SSL_SECURITY_OPTION="--insecure" + else + echo "CA certificates need" + echo "to be fixed for" + echo "using SSL certificate" + echo "verification." + echo "Please fix them i.e." + echo "using security_fixes.sh" + exit 2 + fi + ;; + *) + echo "No Internet connection" + exit 1 + ;; + esac + CURL="curl ${CURL_RETRY} ${SSL_SECURITY_OPTION} --location" + CURL_SILENT="${CURL} --silent --fail" +} + +function installDEBS () { + DEB_REPOSITORIES=( "${@}" ) + TEMP_PATH="/tmp" + for DEB_REPOSITORY in "${DEB_REPOSITORIES[@]}"; do + OLD_IFS="${IFS}" + IFS="|" + PARAMS=(${DEB_REPOSITORY}) + DEBS_URL="${PARAMS[0]}" + DEB_PREFIX="${PARAMS[1]}" + ARCHIVE_FILES="${PARAMS[2]}" + STRIP_COMPONENTS="${PARAMS[3]}" + DEST_DIR="${PARAMS[4]}" + IFS="${OLD_IFS}" + if [ ! -f "${DEST_DIR}/$(echo $ARCHIVE_FILES | sed 's/*//g')" ] + then + DEB_NAMES=$(${CURL_SILENT} "${DEBS_URL}" | grep -oE "\"${DEB_PREFIX}[a-zA-Z0-9%./_+-]*_(armhf|all)\.deb\"" | sed 's/\"//g') + MAX_VERSION="" + MAX_DEB_NAME="" + for DEB_NAME in $DEB_NAMES; do + CURRENT_VERSION=$(echo "${DEB_NAME}" | grep -o '_[a-zA-Z0-9%.+-]*_' | sed 's/_//g') + if [[ "${CURRENT_VERSION}" > "${MAX_VERSION}" ]] + then + MAX_VERSION="${CURRENT_VERSION}" + MAX_DEB_NAME="${DEB_NAME}" + fi + done + [ "${MAX_DEB_NAME}" == "" ] && echo "Error searching for ${DEB_PREFIX} in ${DEBS_URL}" && exit 1 + echo "Downloading ${MAX_DEB_NAME}" + ${CURL} "${DEBS_URL}/${MAX_DEB_NAME}" -o "${TEMP_PATH}/${MAX_DEB_NAME}" + [ ! -f "${TEMP_PATH}/${MAX_DEB_NAME}" ] && echo "Error: no ${TEMP_PATH}/${MAX_DEB_NAME} found." && exit 1 + echo "Extracting ${ARCHIVE_FILES}" + ORIGINAL_DIR="$(pwd)" + cd "${TEMP_PATH}" + rm data.tar.xz > /dev/null 2>&1 + ar -x "${TEMP_PATH}/${MAX_DEB_NAME}" data.tar.xz + cd "${ORIGINAL_DIR}" + rm "${TEMP_PATH}/${MAX_DEB_NAME}" + mkdir -p "${DEST_DIR}" + [ ! -f "${TEMP_PATH}/data.tar.xz" ] && echo "Error: no ${TEMP_PATH}/data.tar.xz found." && exit 1 + tar -xJf "${TEMP_PATH}/data.tar.xz" --wildcards --no-anchored --strip-components="${STRIP_COMPONENTS}" -C "${DEST_DIR}" "${ARCHIVE_FILES}" + rm "${TEMP_PATH}/data.tar.xz" > /dev/null 2>&1 + fi + done +} + +function setupDIALOG { + if which dialog > /dev/null 2>&1 + then + DIALOG="dialog" + else + if [ ! -f /media/fat/linux/dialog/dialog ] + then + setupCURL + installDEBS "http://http.us.debian.org/debian/pool/main/d/dialog|dialog_1.3-2016|dialog|3|/media/fat/linux/dialog" "http://http.us.debian.org/debian/pool/main/n/ncurses|libncursesw5_6.0|libncursesw.so.5*|3|/media/fat/linux/dialog" "http://http.us.debian.org/debian/pool/main/n/ncurses|libtinfo5_6.0|libtinfo.so.5*|3|/media/fat/linux/dialog" + fi + DIALOG="/media/fat/linux/dialog/dialog" + export LD_LIBRARY_PATH="/media/fat/linux/dialog" + fi + + rm -f "/media/fat/config/dialogrc" + if [ ! -f "~/.dialogrc" ] + then + export DIALOGRC="$(dirname ${ORIGINAL_SCRIPT_PATH})/.dialogrc" + if [ ! -f "${DIALOGRC}" ] + then + ${DIALOG} --create-rc "${DIALOGRC}" + sed -i "s/use_colors = OFF/use_colors = ON/g" "${DIALOGRC}" + sed -i "s/screen_color = (CYAN,BLUE,ON)/screen_color = (CYAN,BLACK,ON)/g" "${DIALOGRC}" + sync + fi + fi + + export NCURSES_NO_UTF8_ACS=1 + + : ${DIALOG_OK=0} + : ${DIALOG_CANCEL=1} + : ${DIALOG_HELP=2} + : ${DIALOG_EXTRA=3} + : ${DIALOG_ITEM_HELP=4} + : ${DIALOG_ESC=255} + + : ${SIG_NONE=0} + : ${SIG_HUP=1} + : ${SIG_INT=2} + : ${SIG_QUIT=3} + : ${SIG_KILL=9} + : ${SIG_TERM=15} +} + +function setupDIALOGtempfile { + DIALOG_TEMPFILE=`(DIALOG_TEMPFILE) 2>/dev/null` || DIALOG_TEMPFILE=/tmp/dialog_tempfile$$ + trap "rm -f $DIALOG_TEMPFILE" 0 $SIG_NONE $SIG_HUP $SIG_INT $SIG_QUIT $SIG_TERM +} + +function readDIALOGtempfile { + DIALOG_RETVAL=$? + DIALOG_OUTPUT="$(cat ${DIALOG_TEMPFILE})" + #rm -f ${DIALOG_TEMPFILE} + #unset DIALOG_TEMPFILE +} + +function setupUPDATER { + LOCAL_UPDATER="$(dirname $(readlink -f ${ORIGINAL_SCRIPT_PATH}))/update.sh" + LOCAL_UPDATER_INI="${LOCAL_UPDATER%.*}.ini" + if [ ! -f "${LOCAL_UPDATER}" ] + then + echo "Downloading update.sh" + ${CURL} "$(echo ${UPDATER_URL}?raw=true | sed 's/mister.updater.sh/update.sh/')" -o "${LOCAL_UPDATER}" + [ ! -f "${LOCAL_UPDATER}" ] && echo "Error downloading update.sh" && exit 1 + fi +} + +function setupCoreURLs { + declare -g -A CORE_CATEGORY_NAMES + declare -g -A CORE_CATEGORY_REVERSE_NAMES + declare -g -A COMPUTER_CORE_URLS + declare -g -A CONSOLE_CORE_URLS + declare -g -A ARCADE_CORE_URLS + declare -g -A UTILITY_CORE_URLS + CORE_CATEGORY_NAMES["cores"]="Computer" + CORE_CATEGORY_NAMES["console-cores"]="Console" + CORE_CATEGORY_NAMES["arcade-cores"]="Arcade" + CORE_CATEGORY_NAMES["service-cores"]="Utility" + for CORE_CATEGORY in ${!CORE_CATEGORY_NAMES[@]}; do + CORE_CATEGORY_REVERSE_NAMES["${CORE_CATEGORY_NAMES[${CORE_CATEGORY}]^^}"]="${CORE_CATEGORY}" + done + + echo "Downloading MiSTer Wiki" + CORE_URLS=$(${CURL} "$MISTER_URL/wiki" | awk '/user-content-cores/,/user-content-development/' | grep -io '\(https://github.com/[a-zA-Z0-9./_-]*_MiSTer">[^<]*\)\|\(user-content-[a-z-]*\)') + + + OLD_IFS="$IFS" + IFS=$'\n' + for CORE_URL in $CORE_URLS; do + if [[ $CORE_URL == https://* ]] + then + CORE_NAME="${CORE_URL#*\">}" && CORE_NAME="${CORE_NAME//\'/\\\'}" + CORE_URL="${CORE_URL%\">*}" + [ "${CORE_URL##*\/}" == "Menu_MiSTer" ] && continue + eval ${CORE_CATEGORY_NAMES[$CORE_CATEGORY]^^}_CORE_URLS[${CORE_NAME}]=${CORE_URL} + else + CORE_CATEGORY=$(echo "$CORE_URL" | sed 's/user-content-//g') + fi + done + IFS="$OLD_IFS" +} + +DIALOG_TITLE="MiSTer Core Manager" + +function showPleaseWAIT { + ${DIALOG} --title "${DIALOG_TITLE}" \ + --infobox "Please wait..." 0 0 +} + +function showMainMENU { + setupDIALOGtempfile + ${DIALOG} --clear --no-tags --item-help --ok-label "Select" \ + --title "${DIALOG_TITLE}" \ + --menu "Please choose an option.\nUse arrow keys, tab, space, enter and esc." 0 0 999 \ + "installCOMPUTER" "Install/Update Computer core" "" \ + "deleteCOMPUTER" "Delete Computer core" "" \ + "installCONSOLE" "Install/Update Console core" "" \ + "deleteCONSOLE" "Delete Console core" "" \ + "installARCADE" "Install/Update Arcade core" "" \ + "deleteARCADE" "Delete Arcade core" "" \ + "installUTILITY" "Install/Update Utility core" "" \ + "deleteUTILITY" "Delete Utility core" "" \ + "configureUPDATER" "Configure MiSTer Updater" "Configures ${LOCAL_UPDATER_INI} used both by the updater and by this script" \ + "updateMISTER" "Update MiSTer" "Launches ${LOCAL_UPDATER}" \ + "watchMOVIE" "Watch Star Wars" "Enjoy the show... Press and then in order to exit the movie" \ + 2> ${DIALOG_TEMPFILE} + readDIALOGtempfile +} + +function showInstallMENU { + CORE_CATEGORY_NAME="${1}" + MENU_ITEMS="" + ADDITIONAL_OPTIONS="--no-tags" + OLD_IFS="$IFS" + IFS=$'\n' + for CORE_NAME in $(eval echo \"\${!${CORE_CATEGORY_NAME}_CORE_URLS[*]}\"); do + CORE_URL="$(eval echo \${${CORE_CATEGORY_NAME}_CORE_URLS[${CORE_NAME//\'/\\\'}]})" + MENU_ITEMS="${MENU_ITEMS} \"${CORE_URL}\" \"${CORE_NAME}\"" + done + IFS="$OLD_IFS" + + setupDIALOGtempfile + eval ${DIALOG} --clear --colors --ok-label \"Install/Update\" \ + --extra-button --extra-label \"README\" \ + --title \"${DIALOG_TITLE}: Install/Update ${CORE_CATEGORY_NAME,,} core\" \ + ${ADDITIONAL_OPTIONS} \ + --menu \"Please select the ${CORE_CATEGORY_NAME,,} core you wish to install or update.\" 0 0 999 \ + ${MENU_ITEMS} \ + 2> ${DIALOG_TEMPFILE} + readDIALOGtempfile +} + +function showDeleteMENU { + CORE_CATEGORY_NAME="${1}" + MENU_ITEMS="" + ADDITIONAL_OPTIONS="--no-tags" + for CORE_FILE in "${CORE_CATEGORY_PATHS[${CORE_CATEGORY}]}"/*.rbf; do + MENU_ITEMS="${MENU_ITEMS} \"${CORE_FILE}\" \"${CORE_FILE}\"" + done + + setupDIALOGtempfile + eval ${DIALOG} --clear --colors --ok-label \"Delete\" \ + --title \"${DIALOG_TITLE}: Delete ${CORE_CATEGORY_NAME,,} core\" \ + ${ADDITIONAL_OPTIONS} \ + --menu \"Please select the ${CORE_CATEGORY_NAME,,} core you wish to delete.\" 0 0 999 \ + ${MENU_ITEMS} \ + 2> ${DIALOG_TEMPFILE} + readDIALOGtempfile +} + +clear +checkTERMINAL +setupScriptINI +setupUPDATER +setupDIALOG +setupCoreURLs + +while true; do + showMainMENU + case ${DIALOG_RETVAL} in + ${DIALOG_OK}) + case "${DIALOG_OUTPUT}" in + install*) + CORE_CATEGORY_NAME="${DIALOG_OUTPUT/install/}" + CORE_CATEGORY="${CORE_CATEGORY_REVERSE_NAMES[${CORE_CATEGORY_NAME}]}" + while true; do + showInstallMENU "${CORE_CATEGORY_NAME}" + case ${DIALOG_RETVAL} in + ${DIALOG_OK}) + CORE_URL="${DIALOG_OUTPUT}" + ORIGINAL_DOWNLOAD_NEW_CORES="${DOWNLOAD_NEW_CORES}" + DOWNLOAD_NEW_CORES="true" + ORIGINAL_SSH_CLIENT="${SSH_CLIENT}" + SSH_CLIENT="---" + clear + checkCoreURL + DOWNLOAD_NEW_CORES="${ORIGINAL_DOWNLOAD_NEW_CORES}" + SSH_CLIENT="${ORIGINAL_SSH_CLIENT}" + ;; + ${DIALOG_EXTRA}) + showPleaseWAIT + README_URL="https://github.com$($CURL_SILENT $DIALOG_OUTPUT | grep -oi '/MiSTer-devel/[a-zA-Z0-9./_-]*/blob/[a-zA-Z0-9./_-]*/readme[^"]*')?raw=true" + TMP_README=/tmp/dialog_README_tempfile$$ + $CURL_SILENT "${README_URL}" | dos2unix > "${TMP_README}" + if [ -f "${TMP_README}" ] + then + ${DIALOG} --clear --title "${DIALOG_TITLE}" \ + --textbox "${TMP_README}" 0 0 + rm -f "${TMP_README}" + else + ${DIALOG} --clear --title "${DIALOG_TITLE}" \ + --msgbox "Something went wrong downloading\n${README_URL}" 0 0 + fi + ;; + *) + break + ;; + esac + done + ;; + delete*) + CORE_CATEGORY_NAME="${DIALOG_OUTPUT/delete/}" + CORE_CATEGORY="${CORE_CATEGORY_REVERSE_NAMES[${CORE_CATEGORY_NAME}]}" + while true; do + showDeleteMENU "${CORE_CATEGORY_NAME}" + case ${DIALOG_RETVAL} in + ${DIALOG_OK}) + ${DIALOG} --clear --title "${DIALOG_TITLE}" --defaultno --yesno "Are you sure you want to delete\n${DIALOG_OUTPUT}\n???" 0 0 && rm -f "${DIALOG_OUTPUT}" && sync + ;; + *) + break + ;; + esac + done + ;; + configureUPDATER) + ${DIALOG} --title "${DIALOG_TITLE}" \ + --msgbox "Coming soon...\n\n...in the meantime you can watch Star Wars" 0 0 + ;; + updateMISTER) + clear + ${LOCAL_UPDATER} + ;; + watchMOVIE) + clear + telnet towel.blinkenlights.nl + ;; + esac + ;; + *) + break;; + esac +done + +clear + +exit 0