From b768714e0f31fe2450443dd0787d94ee3ec43739 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sun, 19 Jan 2025 17:23:50 -0600 Subject: [PATCH 01/14] everything should be functional --- api | 33 +++++++++++++++++++++------------ manage | 56 +++++++++++++++++++++++++++++++++++++++----------------- updater | 14 ++++++++------ 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/api b/api index da0a306428..c0c2fac45a 100755 --- a/api +++ b/api @@ -1595,9 +1595,11 @@ will_reinstall() { #return 0 if $1 app will be reinstalled during an update, oth [ -z "$app" ] && error 'will_reinstall(): requires an argument' #exit immediately if app is not installed. - if [ "$(app_status "$app")" != 'installed' ];then - return 1 - fi + #if [ "$(app_status "$app")" != 'installed' ];then + # return 1 + #fi + #it seems that the above code was added for speed alone https://github.com/Botspot/pi-apps/commit/d8bfc3f5fc9b42060bfbd68a11b24f66246d61bc + #commenting it out allows retrying failed app update where uninstall succeeds but install fails #detect which installation script exists - both for local install and for update directory local local_scriptname="$(script_name_cpu "$app")" @@ -2919,16 +2921,19 @@ send_error_report() { #non-interactively send a Pi-Apps error log file to the Bo } -diagnose_apps() { #Given a list of apps that failed to install/uninstall, loop through each error log, diagnose it, and provide a "Send report" button if applicable. - local failed_apps="$1" +diagnose_apps() { #Given a list of action;app that failed to install/uninstall, loop through each error log, diagnose it, and provide a "Send report" button if applicable. + local failure_list="$1" local IFS=$'\n' - local num_lines="$(grep . <<<"$failed_apps" | wc -l)" - local i=1 #counter to track which failed_app in the list is current - local app + local num_lines="$(grep . <<<"$failure_list" | wc -l)" + local i=1 #counter to track which line in the list is current + local line local button - for app in $failed_apps ;do + for line in $failure_list ;do + local action="$(echo "$line" | awk -F';' '{print $1}')" + local app="$(echo "$line" | awk -F';' '{print $2}')" + local logfile="$(get_logfile "$app")" #given the app's logfile, categorize the error and set the error_type variable local diagnosis="$(log_diagnose "$logfile" "allowwrite")" @@ -2958,7 +2963,7 @@ diagnose_apps() { #Given a list of apps that failed to install/uninstall, loop t text+=$'\n'"Error report cannot be sent because your system is unsupported." else #if all of the above checks evaluate to FALSE, then display the "Send report" button. - local send_button=(--button='Send report'!"${DIRECTORY}/icons/send-error-report.png":2) + local send_button=(--button='Send report'!"${DIRECTORY}/icons/send-error-report.png"!"Send this logfile to Pi-Apps developers for review":2) fi #display support links, depending on if this was a package-app or a script-app @@ -2981,7 +2986,7 @@ diagnose_apps() { #Given a list of apps that failed to install/uninstall, loop t error_caption="$(echo "$unsupported_message" | sed "s/\x1b\[[0-9;]*[a-zA-Z]//g")"$'\n'$'\n'"$error_caption" fi - #this dialog may be one in a series of failed_app dialogs. Name the window-close button accordingly. + #this dialog may be one in a series of diagnosis dialogs. Name the window-close button accordingly. if [ $i -lt $num_lines ];then local close_button=(--button="Next error!${DIRECTORY}/icons/forward.png":1) else @@ -2993,12 +2998,16 @@ diagnose_apps() { #Given a list of apps that failed to install/uninstall, loop t --text="$text" --wrap --fontname=12 \ --button='View log'!"${DIRECTORY}/icons/log-file.png"!"Review the output from when $app tried to $action.":"bash -c 'view_file "\""$logfile"\""'" \ "${send_button[@]}" \ - "${close_button[@]}" + --button="Retry!${DIRECTORY}/icons/refresh.png"!"Try $(echo "${action}ing" | sed 's/updateing/updating/g') $app again.":3 \ + "${close_button[@]}" >/dev/null button="${PIPESTATUS[1]}" if [ $button == 2 ];then #send error log send_error_report "$logfile" + elif [ $button == 3 ];then + #retry button clicked, return new queue line(s) back to manage daemon + echo "$line" fi i=$((i+1)) diff --git a/manage b/manage index 7d76da7a7c..f985cf7ed4 100755 --- a/manage +++ b/manage @@ -438,7 +438,7 @@ $app" while true;do #repeat until nothing is left in the queue #check for new actions to be executed - echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent cat from hanging if the queue file is empty + echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" # tac reverses the order of the list. a plain cat of the file will give the newest item in the queue first. #keep track of all actions for this session with the $queue variable @@ -447,7 +447,33 @@ $app" elif [ ! -z "$new_lines" ];then # add new_lines to queue if new_lines is not empty queue+=$'\n'"$new_lines" fi - + + #check if queue is complete - diagnose apps and provide the opportunity to retry failed actions, otherwise exit loop + if [ "${current_line_num}" -gt "$(echo "$queue" | wc -l)" ];then + #diagnose every failed app's logfile - list item format is $action;$app;$exitcode + failed_apps="$(echo "$queue" | grep ';1$' | sed 's/;1$//g')" + retry_apps="$(diagnose_apps "$failed_apps")" + if [ -z "$retry_apps" ];then + #user chose to not retry the failed action(s). + #edge case: user may have added more actions while the diagnosis window was open. Check for this, and if nothing found, exit loop + echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty + new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" + if [ -z "$new_lines" ];then + break + else + #Replace past '1' exit codes with "diagnosed" to avoid repeated diagnosis + queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + #user added more actions while the diagnosis window was open + queue+=$'\n'"$new_lines" + fi + else + #user chose to retry action(s). Replace '1' exit codes with "diagnosed" to avoid repeated diagnosis + queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + #and now add to queue the actions we want to retry. + queue+=$'\n'"$retry_apps" + fi + fi + # reorder queue list to prioritize app refresh and file update actions queue="$(reorder_list "$queue")" @@ -455,12 +481,6 @@ $app" source "${DIRECTORY}/updater" source sourced_updater=1 fi - #echo "length of queue is $(echo "$queue" | wc -l)" - - #exit loop if queue is complete and no new actions were added to the queue - if [ "${current_line_num}" -gt "$(echo "$queue" | wc -l)" ];then - break - fi #echo "current position in queue is ${current_line_num}" #echo "queue is '$queue'" @@ -481,13 +501,13 @@ $app" write_list_pid=$! #secondary list-writing background process - kill it if it exists because write_list just sent a newer version of the list to yad - [ ! -z "$secondary_write_list_pid" ] && process_exists "$secondary_write_list_pid" && kill "$secondary_write_list_pid" + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null else #if app1 is refreshed and app2 is then reinstalled, the list would only say app1 is bring refreshed for the entirety of app2's reinstallation, due to the process-skipping. #launch a secondary background process that waits for $write_list_pid to finish #only allow one secondary background process to run; kill previous jobs and start a new one - [ ! -z "$secondary_write_list_pid" ] && process_exists "$secondary_write_list_pid" && kill "$secondary_write_list_pid" + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null (while process_exists $write_list_pid ;do sleep 1 ;done ; write_list "$queue") & secondary_write_list_pid=$! fi @@ -500,17 +520,23 @@ $app" exitcode=$? elif [ "$action" == refresh ];then #Set terminal title - echo -ne "\e]0;${action^}ing ${app}\a" + echo -ne "\e]0;Refreshing ${app}\a" refresh_app "$app" exitcode=$? + elif [ "$action" == update ];then #manage can handle this action, but avoid spawning subprocess + #Set terminal title + echo -ne "\e]0;Updating ${app}\a" + update_app "$app" + exitcode=$? else #Set terminal title - echo -ne "\e]0;${action^}ing ${app}\a" | sed 's/Updateing/Updating/g' + echo -ne "\e]0;${action^}ing ${app}\a" "${DIRECTORY}/manage" "$action" "$app" exitcode=$? fi #record exit code in current line of $queue + [ "$exitcode" != 0 ] && exitcode=1 #for easier regex and sed lines, force non-zero exit codes to be 1 queue="$(echo "$queue" | sed "${current_line_num}s/;in-progress$/;$exitcode/")" #one more line of $queue has been completed. @@ -518,7 +544,7 @@ $app" done #refresh the list in queue-viewer window for the final time with all actions complete - [ ! -z "$secondary_write_list_pid" ] && process_exists "$secondary_write_list_pid" && kill "$secondary_write_list_pid" #kill secondary list writer + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null #kill secondary list writer wait $write_list_pid write_list "$queue" @@ -535,10 +561,6 @@ ${DIRECTORY}/icons/none-1.png #close the queue-viewer window in a few seconds (sleep 5; kill $yadpid 2>/dev/null) & - #diagnose every failed app's logfile - list item format is $action;$app;$exitcode - failed_apps="$(echo "$queue" | grep ';1$' | awk -F';' '{print $2}')" - diagnose_apps "$failed_apps" - # if update refresh or update-file actions were run then update the .git folder if [ "$sourced_updater" == 1 ]; then update_git diff --git a/updater b/updater index 1e1591be89..867b273810 100755 --- a/updater +++ b/updater @@ -441,7 +441,7 @@ update_app() { #first arg is app name #Set terminal title echo -ne "\e]0;Updating ${app}\a" - + # check if update app folder exists before doing anything # it can happen that executing the updater from the pi-apps GUI the update folder is missing # if the user has no internet or internet issues the update folder will be removed due to the failed git pull and then wait in the loop for a new git clone @@ -452,15 +452,17 @@ update_app() { #first arg is app name if will_reinstall "$app";then installback=yes status "$app's install script has been updated. Reinstalling $app..." - #uninstall it - "${DIRECTORY}/manage" uninstall "$app" update #report to the app uninstall script that this is an uninstall for the purpose of updating by passing "update" + #uninstall it - if retrying an update with successful uninstall and failed install, don't uninstall again + if [ "$(app_status "$app")" != uninstalled ];then + "${DIRECTORY}/manage" uninstall "$app" update #report to the app uninstall script that this is an uninstall for the purpose of updating by passing "update" + fi #fix edge case: if app is installed but uninstall script doesn't exist somehow, then pretend app was uninstalled so that the reinstall later will happen noninteractively if [ "$(app_status "$app")" == installed ];then echo 'uninstalled' > "${DIRECTORY}/data/status/${app}" fi fi - + no_status=true refresh_app "$app" failed=false @@ -558,7 +560,7 @@ update_now_gui_apps() { # deprecated function that is only here so old updater s #load the app list now to reduce launch time refresh_app_list & - action=update diagnose_apps "$failed_apps" + diagnose_apps "$(echo "$failed_apps" | sed 's/^/update;/g')" } update_now_gui() { #input: updatable_files and updatable_apps variables @@ -620,7 +622,7 @@ update_now_background() { #input: updatable_apps and updatable_files variables elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/install-${arch}" ] && [ ! -f "${DIRECTORY}/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/packages" ]; then continue # if app will be reinstalled then don't try to reinstall it in the background - elif will_reinstall "$app"; then + elif [ "$(app_status "${app}")" == 'installed' ];then continue # if app failed to install last time, show this app refresh to the user. elif [ "$(app_status "${app}")" == 'corrupted' ];then From 8dac50cea92d5869735466f6c50f00d2dcc85688 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:08:31 -0600 Subject: [PATCH 02/14] manage daemon run terminal to change window order This has bothered me ever since bookworm dropped. Now terminal appears after queueviewer window, thus, on top of it. No more half occluded terminal. This also prepares for a summary window from "Contributor update" to appear after the terminal closes. --- api | 51 ++++++++++++--------------------------------------- manage | 54 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 57 deletions(-) diff --git a/api b/api index c0c2fac45a..c56fd1a4ae 100755 --- a/api +++ b/api @@ -1081,51 +1081,24 @@ terminal_manage() { # wrapper for the original terminal_manage function to termi terminal_manage_multi "$action $app" } -terminal_manage_multi() { #function to install/uninstall/update/refresh multiple apps (or filelists) - uses a terminal and refreshes the app list - queue="$1" #one or multiple actions and app names (or filelists of the format 'filelist:path/to/file:path/to/another/file') +terminal_manage_multi() { #function to install/uninstall/update/refresh multiple apps (or filelists) - refreshes the app list + local queue="$1" #one or multiple actions and app names #To prevent multiple simultaneous manage instances, use the 'daemon' mode. This will create a queue of actions that are executed concurrently. - #The first daemon instance is the 'master' process. Subsequent processes will add the action to the queue and then exit. + #The first daemon instance is the 'master' process, which opens a terminal. Subsequent processes will add the action to the queue and then exit. #All output is generated by the 'master' daemon process. Subsequent processes shouldn't open a terminal, because the master one is already open. if [ -f "${DIRECTORY}/data/manage-daemon/pid" ] && process_exists $(cat "${DIRECTORY}/data/manage-daemon/pid") ;then - #The 'master' daemon is already running. Avoid launching a second terminal. + #daemon already running, send queue to it and exit "${DIRECTORY}/manage" daemon "$queue" else - #in a terminal, first get the api functions, display the pi-apps logo, run the manage script, and refresh the app list if the $pipe variable is set - "${DIRECTORY}/etc/terminal-run" ' - DIRECTORY="'"$DIRECTORY"'" - export geometry2="'"$geometry2"'" - source "${DIRECTORY}/api" - generate_logo - - refresh_list() { #Refresh the current list of apps in the event of a change - if [ ! -z "'"$pipe"'" ] && [ -p "'"$pipe"'" ];then - echo -e "\f" > "'"$pipe"'" - "${DIRECTORY}/preload" "$(cat "${DIRECTORY}/data/settings/App List Style")" "'"$prefix"'" > "'"$pipe"'" 2>/dev/null - fi - } - - "${DIRECTORY}/manage" daemon "'"$queue"'" - - #refresh app list - refresh_list - - for i in {30..1} ;do - echo -en "You can close this window now. Auto-closing in $i seconds.\e[0K\r" - sleep 1 - done - ' "Terminal Output" - - # Check if terminal-run failed to launch. GUI users don't see any terminal output if it fails (since there is no terminal open) so we need to prompt them with a GUI window - if [ "$?" != 0 ]; then - echo -e "Unable to open a terminal.\nDebug output below.\n$(DEBUG=1 "${DIRECTORY}/etc/terminal-run" 2>&1)" | yad --center --window-icon="${DIRECTORY}/icons/logo.png" \ - --width=700 --height=300 --text-info --title="Error occured when calling terminal-run" \ - --image="${DIRECTORY}/icons/error.png" --image-on-top --fontname=12 \ - --button='OK' - if echo "$queue" | grep -q "^update filelist:" ;then #list of files separated by : - updatable_apps='' updatable_files="$(echo "$queue" | grep "^update filelist:" | sed 's/^update filelist://g' | tr ':' '\n')" no_status=true update_now_cli - fi + #this function is running the daemon, so once it exits refresh the pi-apps list + "${DIRECTORY}/manage" daemon "$queue" + + #refresh app list + if [ ! -z "$pipe" ] && [ -p "$pipe" ];then + echo -e '\f' > "$pipe" + "${DIRECTORY}/preload" "$(cat "${DIRECTORY}/data/settings/App List Style")" "$prefix" > "$pipe" 2>/dev/null fi fi } @@ -2963,7 +2936,7 @@ diagnose_apps() { #Given a list of action;app that failed to install/uninstall, text+=$'\n'"Error report cannot be sent because your system is unsupported." else #if all of the above checks evaluate to FALSE, then display the "Send report" button. - local send_button=(--button='Send report'!"${DIRECTORY}/icons/send-error-report.png"!"Send this logfile to Pi-Apps developers for review":2) + local send_button=(--button='Send report'!"${DIRECTORY}/icons/send-error-report.png"!"Send this log file to Pi-Apps developers for review":2) fi #display support links, depending on if this was a package-app or a script-app diff --git a/manage b/manage index f985cf7ed4..c2e0cd245f 100755 --- a/manage +++ b/manage @@ -417,9 +417,9 @@ $app" fi fi - [ -z "$geometry2" ] && geometry2='--center' + [ -z "$geometry2" ] && geometry2='--center --width=330 --height=400' - tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Monitor Progress' \ + tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" "$geometry2" --title='Monitor Progress' \ --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ --dclick-action=true --select-action=true \ @@ -428,13 +428,19 @@ $app" trap "kill $yadpid 2>/dev/null" EXIT + "${DIRECTORY}/etc/terminal-run" ' + DIRECTORY="'"$DIRECTORY"'" + source "${DIRECTORY}/api" + generate_logo + + queue="" + #Used to track which line of $queue is currently being dealt with. current_line_num=1 sourced_updater=0 #updater script needs to be sourced if files are updated. This allows it to only be sourced once. - queue='' - IFS=$'\n' + IFS=$'\''\n'\'' while true;do #repeat until nothing is left in the queue #check for new actions to be executed @@ -445,13 +451,13 @@ $app" if [ -z "$queue" ];then queue="$new_lines" elif [ ! -z "$new_lines" ];then # add new_lines to queue if new_lines is not empty - queue+=$'\n'"$new_lines" + queue+=$'\''\n'\''"$new_lines" fi #check if queue is complete - diagnose apps and provide the opportunity to retry failed actions, otherwise exit loop if [ "${current_line_num}" -gt "$(echo "$queue" | wc -l)" ];then - #diagnose every failed app's logfile - list item format is $action;$app;$exitcode - failed_apps="$(echo "$queue" | grep ';1$' | sed 's/;1$//g')" + #diagnose every failed apps logfile - list item format is $action;$app;$exitcode + failed_apps="$(echo "$queue" | grep '\'';1$'\'' | sed '\''s/;1$//g'\'')" retry_apps="$(diagnose_apps "$failed_apps")" if [ -z "$retry_apps" ];then #user chose to not retry the failed action(s). @@ -462,15 +468,15 @@ $app" break else #Replace past '1' exit codes with "diagnosed" to avoid repeated diagnosis - queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + queue="$(echo "$queue" | sed '\''s/;1$/;diagnosed/g'\'')" #user added more actions while the diagnosis window was open - queue+=$'\n'"$new_lines" + queue+=$'\''\n'\''"$new_lines" fi else #user chose to retry action(s). Replace '1' exit codes with "diagnosed" to avoid repeated diagnosis - queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + queue="$(echo "$queue" | sed '\''s/;1$/;diagnosed/g'\'')" #and now add to queue the actions we want to retry. - queue+=$'\n'"$retry_apps" + queue+=$'\''\n'\''"$retry_apps" fi fi @@ -483,19 +489,19 @@ $app" fi #echo "current position in queue is ${current_line_num}" - #echo "queue is '$queue'" + #echo "queue is $queue" line="$(echo "$queue" | sed -n "${current_line_num}"p)" - #echo "Now handling request: '$line'" + #echo "Now handling request: $line" #indicate current action in current line of $queue queue="$(echo "$queue" | sed "${current_line_num}s/$/;in-progress/")" #get first word of this line - the action. Subsequent words are the name of the app. - action="$(echo "$line" | awk -F';' '{print $1}')" - app="$(echo "$line" | awk -F';' '{print $2}')" + action="$(echo "$line" | awk -F'\'';'\'' '\''{print $1}'\'')" + app="$(echo "$line" | awk -F'\'';'\'' '\''{print $2}'\'')" - #refresh the list in queue-viewer window as a background process - skip it if the list is still refreshing from last loop iteration; in game dev this is 'dropped input' + #refresh the list in queue-viewer window as a background process - skip it if the list is still refreshing from last loop iteration; in game dev this is "dropped input" if [ -z "$write_list_pid" ] || ! process_exists "$write_list_pid" ;then write_list "$queue" & write_list_pid=$! @@ -503,7 +509,7 @@ $app" #secondary list-writing background process - kill it if it exists because write_list just sent a newer version of the list to yad [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null else - #if app1 is refreshed and app2 is then reinstalled, the list would only say app1 is bring refreshed for the entirety of app2's reinstallation, due to the process-skipping. + #if app1 is refreshed and app2 is then reinstalled, the list would only say app1 is bring refreshed for the entirety of app2s reinstallation, due to the process-skipping. #launch a secondary background process that waits for $write_list_pid to finish #only allow one secondary background process to run; kill previous jobs and start a new one @@ -559,7 +565,19 @@ ${DIRECTORY}/icons/none-1.png rm -f "${DIRECTORY}/data/manage-daemon/pid" #close the queue-viewer window in a few seconds - (sleep 5; kill $yadpid 2>/dev/null) & + (sleep 5; kill $yadpid 2>/dev/null) &' "Terminal Output" + + # Check if terminal-run failed to launch. GUI users don't see any terminal output if it fails (since there is no terminal open) so we need to prompt them with a GUI window + if [ "$?" != 0 ]; then + echo -e "Unable to open a terminal.\nDebug output below.\n$(DEBUG=1 "${DIRECTORY}/etc/terminal-run" 2>&1)" | yad --class Pi-Apps --name "Pi-Apps" --center --window-icon="${DIRECTORY}/icons/logo.png" \ + --width=700 --height=300 --text-info --title="Error occured when calling terminal-run" \ + --image="${DIRECTORY}/icons/error.png" --image-on-top --fontname=12 \ + --button='OK' + if echo "$queue" | grep -q "^update-file;" ;then + typeset -f update_now_cli &>/dev/null || source "${DIRECTORY}/updater" source + updatable_apps='' updatable_files="$(echo "$queue" | grep "^update-file;" | sed 's/^update-file;//g')" update_now_cli + fi + fi # if update refresh or update-file actions were run then update the .git folder if [ "$sourced_updater" == 1 ]; then From a0d7fdae97e60773dcc64535518f40d700285edc Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:10:21 -0600 Subject: [PATCH 03/14] remove last mention of filelist since we don't use it --- api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api b/api index c56fd1a4ae..a85a141224 100755 --- a/api +++ b/api @@ -1081,7 +1081,7 @@ terminal_manage() { # wrapper for the original terminal_manage function to termi terminal_manage_multi "$action $app" } -terminal_manage_multi() { #function to install/uninstall/update/refresh multiple apps (or filelists) - refreshes the app list +terminal_manage_multi() { #function to install/uninstall/update/refresh multiple apps - refreshes the app list if applicable local queue="$1" #one or multiple actions and app names #To prevent multiple simultaneous manage instances, use the 'daemon' mode. This will create a queue of actions that are executed concurrently. From 611f36532558e318735e7ed720e05a98bdb91087 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:29:07 -0600 Subject: [PATCH 04/14] use function in terminal Also, fix sourcing the other manage daemon functions like reorder_list --- manage | 380 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 197 insertions(+), 183 deletions(-) diff --git a/manage b/manage index c2e0cd245f..c2acd1bb24 100755 --- a/manage +++ b/manage @@ -4,7 +4,7 @@ #$1 is an action, like install #$2 is app name, like Arduino -DIRECTORY="$(readlink -f "$(dirname "$0")")" +[ -z "$DIRECTORY" ] && DIRECTORY="$(readlink -f "$(dirname "$0")")" function error { echo -e "\e[91m$1\e[39m" @@ -19,24 +19,6 @@ if [ -z "$1" ];then error "You need to specify an operation, and in most cases, which app to operate on." fi -set -a #make all functions in the api available to apps -source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api" - -#run is_supported_system once mostly to check for unsupported ubuntu/debian distros and warn the user with a blocking GUI popup -runonce <<"EOF" - if ! is_supported_system >/dev/null;then - text="YOUR SYSTEM IS UNSUPPORTED: -$(is_supported_system) - -Pi-Apps will disable the sending of any error reports until you have resolved the issue above. -Your mileage may vary with using Pi-Apps in this state. Expect the majority of apps to be broken." - - yadflags=(--class Pi-Apps --name "Pi-Apps" --window-icon="${DIRECTORY}/icons/logo.png" --title="Pi-Apps") - userinput_func "$text" "Ok" - fi - true -EOF - validate_apps_gui() { #Given a list of actions and apps, graphically notify the user if there is a problem or ask for confirmation. Result is sent to stdout. #action and app are separated by semicolon. (;) #example line of input on $1: "install;Zoom" @@ -161,21 +143,40 @@ validate_apps_gui() { #Given a list of actions and apps, graphically notify the echo "$queue" } +if [ "$1" != daemon ] || [ "$2" != source ];then + set -a #make all functions in the api available to apps + source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api" + + #run is_supported_system once mostly to check for unsupported ubuntu/debian distros and warn the user with a blocking GUI popup + runonce <<"EOF" + if ! is_supported_system >/dev/null;then + text="YOUR SYSTEM IS UNSUPPORTED: +$(is_supported_system) + +Pi-Apps will disable the sending of any error reports until you have resolved the issue above. +Your mileage may vary with using Pi-Apps in this state. Expect the majority of apps to be broken." + + yadflags=(--class Pi-Apps --name "Pi-Apps" --window-icon="${DIRECTORY}/icons/logo.png" --title="Pi-Apps") + userinput_func "$text" "Ok" + fi + true +EOF + #remove old mcpi repositories - this runonce is here so that terminal-only users will still receive the fix. (runonce <<"EOF" - if [ -f /etc/apt/sources.list.d/Alvarito050506_mcpi-devs.list ];then - sudo rm -f /etc/apt/sources.list.d/Alvarito050506_mcpi-devs.list - fi - if [ -f /etc/apt/sources.list.d/mcpi-revival.list ];then - sudo rm -f /etc/apt/sources.list.d/mcpi-revival.list - sudo rm -f /etc/apt/trusted.gpg.d/mcpi-revival.gpg - fi - - if dpkg -l box86-no-binfmt-restart &>/dev/null ;then - sudo apt purge -y box86-no-binfmt-restart - sudo apt update - sudo apt install -y box86 - fi +if [ -f /etc/apt/sources.list.d/Alvarito050506_mcpi-devs.list ];then + sudo rm -f /etc/apt/sources.list.d/Alvarito050506_mcpi-devs.list +fi +if [ -f /etc/apt/sources.list.d/mcpi-revival.list ];then + sudo rm -f /etc/apt/sources.list.d/mcpi-revival.list + sudo rm -f /etc/apt/trusted.gpg.d/mcpi-revival.gpg +fi + +if dpkg -l box86-no-binfmt-restart &>/dev/null ;then + sudo apt purge -y box86-no-binfmt-restart + sudo apt update + sudo apt install -y box86 +fi EOF ) &>/dev/null @@ -191,11 +192,13 @@ if [ ! -z "$removal_list" ]; then echo "$removal_list" | xargs sudo rm -f fi -mkdir -p "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status" "${DIRECTORY}/logs" - #remove week-old logfiles find "${DIRECTORY}/logs" -type f -mtime +6 -exec rm -f {} \; &>/dev/null & +mkdir -p "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status" "${DIRECTORY}/logs" + +fi #skip everything above if sourcing manage daemon + #check if hardware and OS is supported if [ "$1" != 'daemon' ]; then if [ "$supported" == "yes" ] || [ "$supported" == "no" ]; then @@ -211,6 +214,8 @@ if [ "$1" != 'daemon' ]; then fi fi + + if [ "$1" == 'daemon' ];then #Daemon to run in the background and install/uninstall/update apps as the user makes selections #This allows the user to queue up a list of actions that will run sequentially. @@ -353,6 +358,157 @@ $app" echo "$queue_reordered" } + manage_daemon_terminal_code() { #all manage-daemon terminal code runs here + #check if hardware and OS is supported + unsupported_message="$(is_supported_system)" + if [ $? == 0 ];then + export supported=yes + export unsupported_message='' + else + export supported=no + export unsupported_message + fi + + queue="" + + #Used to track which line of $queue is currently being dealt with. + current_line_num=1 + + sourced_updater=0 #updater script needs to be sourced if files are updated. This allows it to only be sourced once. + + IFS=$'\n' + while true;do #repeat until nothing is left in the queue + + #check for new actions to be executed + echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty + new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" # tac reverses the order of the list. a plain cat of the file will give the newest item in the queue first. + + #keep track of all actions for this session with the $queue variable + if [ -z "$queue" ];then + queue="$new_lines" + elif [ ! -z "$new_lines" ];then # add new_lines to queue if new_lines is not empty + queue+=$'\n'"$new_lines" + fi + + #check if queue is complete - diagnose apps and provide the opportunity to retry failed actions, otherwise exit loop + if [ "${current_line_num}" -gt "$(echo "$queue" | wc -l)" ];then + #diagnose every failed apps logfile - list item format is $action;$app;$exitcode + failed_apps="$(echo "$queue" | grep ';1$' | sed 's/;1$//g')" + retry_apps="$(diagnose_apps "$failed_apps")" + if [ -z "$retry_apps" ];then + #user chose to not retry the failed action(s). + #edge case: user may have added more actions while the diagnosis window was open. Check for this, and if nothing found, exit loop + echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty + new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" + if [ -z "$new_lines" ];then + break + else + #Replace past '1' exit codes with "diagnosed" to avoid repeated diagnosis + queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + #user added more actions while the diagnosis window was open + queue+=$'\n'"$new_lines" + fi + else + #user chose to retry action(s). Replace '1' exit codes with "diagnosed" to avoid repeated diagnosis + queue="$(echo "$queue" | sed 's/;1$/;diagnosed/g')" + #and now add to queue the actions we want to retry. + queue+=$'\n'"$retry_apps" + fi + fi + + # reorder queue list to prioritize app refresh and file update actions + queue="$(reorder_list "$queue")" + + if [ ! -z "$new_lines" ] && [ "$sourced_updater" == 0 ] && grep -q "update\|refresh\|update-file" <<<"$new_lines" ;then #source updater if necessary + source "${DIRECTORY}/updater" source + sourced_updater=1 + fi + + #echo "current position in queue is ${current_line_num}" + #echo "queue is $queue" + + line="$(echo "$queue" | sed -n "${current_line_num}"p)" + #echo "Now handling request: $line" + + #indicate current action in current line of $queue + queue="$(echo "$queue" | sed "${current_line_num}s/$/;in-progress/")" + + #get first word of this line - the action. Subsequent words are the name of the app. + action="$(echo "$line" | awk -F';' '{print $1}')" + app="$(echo "$line" | awk -F';' '{print $2}')" + + #refresh the list in queue-viewer window as a background process - skip it if the list is still refreshing from last loop iteration; in game dev this is "dropped input" + if [ -z "$write_list_pid" ] || ! process_exists "$write_list_pid" ;then + write_list "$queue" & + write_list_pid=$! + + #secondary list-writing background process - kill it if it exists because write_list just sent a newer version of the list to yad + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null + else + #if app1 is refreshed and app2 is then reinstalled, the list would only say app1 is bring refreshed for the entirety of app2s reinstallation, due to the process-skipping. + #launch a secondary background process that waits for $write_list_pid to finish + + #only allow one secondary background process to run; kill previous jobs and start a new one + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null + (while process_exists $write_list_pid ;do sleep 1 ;done ; write_list "$queue") & + secondary_write_list_pid=$! + fi + + #run manage script for app installs, uninstalls, or updates. Avoid using it for file-updates and refreshes because that is out of the scope for manage script. + if [ "$action" == update-file ];then + #Set terminal title + echo -ne "\e]0;Updating ${app} file\a" + update_file "$app" + exitcode=$? + elif [ "$action" == refresh ];then + #Set terminal title + echo -ne "\e]0;Refreshing ${app}\a" + refresh_app "$app" + exitcode=$? + elif [ "$action" == update ];then #manage can handle this action, but avoid spawning subprocess + #Set terminal title + echo -ne "\e]0;Updating ${app}\a" + update_app "$app" + exitcode=$? + else + #Set terminal title + echo -ne "\e]0;${action^}ing ${app}\a" + "${DIRECTORY}/manage" "$action" "$app" + exitcode=$? + fi + + #record exit code in current line of $queue + [ "$exitcode" != 0 ] && exitcode=1 #for easier regex and sed lines, force non-zero exit codes to be 1 + queue="$(echo "$queue" | sed "${current_line_num}s/;in-progress$/;$exitcode/")" + + #one more line of $queue has been completed. + current_line_num=$((current_line_num+1)) + done + + #refresh the list in queue-viewer window for the final time with all actions complete + [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null #kill secondary list writer + wait $write_list_pid + write_list "$queue" + + #before exiting the loop, add a line to the queue-viewer window indicating that all items have completed. + echo "${DIRECTORY}/icons/none-1.png +${DIRECTORY}/icons/none-1.png +Done. +${DIRECTORY}/icons/none-1.png +" > "${DIRECTORY}/data/manage-daemon/yadlist" + + #all actions have been completed. Daemon has effectively stopped listening, so remove its pid file + rm -f "${DIRECTORY}/data/manage-daemon/pid" + + #close the queue-viewer window in a few seconds + (sleep 5; kill $yadpid 2>/dev/null) & + } + + if [ "$2" == source ];then + #this script can be sourced to get functions: source "${DIRECTORY}/manage" daemon source + return 0 + fi + #make a named pipe so that other daemon processes can notify this master daemon process to complete new tasks if [ ! -e "${DIRECTORY}/data/manage-daemon/queue" ];then mkfifo "${DIRECTORY}/data/manage-daemon/queue" @@ -403,23 +559,10 @@ $app" #Another named pipe is created to refresh the yad list later. rm -f "${DIRECTORY}/data/manage-daemon/yadlist" mkfifo "${DIRECTORY}/data/manage-daemon/yadlist" #make a named pipe - - #check if hardware and OS is supported - if [ "$supported" == "yes" ] || [ "$supported" == "no" ]; then - true - else - if is_supported_system >/dev/null;then - export supported=yes - export unsupported_message='' - else - export supported=no - export unsupported_message="$(is_supported_system)" - fi - fi - [ -z "$geometry2" ] && geometry2='--center --width=330 --height=400' + [ -z "$geometry2" ] && geometry2='--center' - tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" "$geometry2" --title='Monitor Progress' \ + tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Monitor Progress' \ --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ --dclick-action=true --select-action=true \ @@ -429,143 +572,14 @@ $app" trap "kill $yadpid 2>/dev/null" EXIT "${DIRECTORY}/etc/terminal-run" ' - DIRECTORY="'"$DIRECTORY"'" + trap "sleep 5" EXIT + export DIRECTORY="'"$DIRECTORY"'" source "${DIRECTORY}/api" generate_logo - queue="" - - #Used to track which line of $queue is currently being dealt with. - current_line_num=1 + source "${DIRECTORY}/manage" daemon source - sourced_updater=0 #updater script needs to be sourced if files are updated. This allows it to only be sourced once. - - IFS=$'\''\n'\'' - while true;do #repeat until nothing is left in the queue - - #check for new actions to be executed - echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty - new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" # tac reverses the order of the list. a plain cat of the file will give the newest item in the queue first. - - #keep track of all actions for this session with the $queue variable - if [ -z "$queue" ];then - queue="$new_lines" - elif [ ! -z "$new_lines" ];then # add new_lines to queue if new_lines is not empty - queue+=$'\''\n'\''"$new_lines" - fi - - #check if queue is complete - diagnose apps and provide the opportunity to retry failed actions, otherwise exit loop - if [ "${current_line_num}" -gt "$(echo "$queue" | wc -l)" ];then - #diagnose every failed apps logfile - list item format is $action;$app;$exitcode - failed_apps="$(echo "$queue" | grep '\'';1$'\'' | sed '\''s/;1$//g'\'')" - retry_apps="$(diagnose_apps "$failed_apps")" - if [ -z "$retry_apps" ];then - #user chose to not retry the failed action(s). - #edge case: user may have added more actions while the diagnosis window was open. Check for this, and if nothing found, exit loop - echo -n > "${DIRECTORY}/data/manage-daemon/queue" & #ensure that the pipe is in write mode to prevent tac from hanging if the queue file is empty - new_lines="$(tac "${DIRECTORY}/data/manage-daemon/queue")" - if [ -z "$new_lines" ];then - break - else - #Replace past '1' exit codes with "diagnosed" to avoid repeated diagnosis - queue="$(echo "$queue" | sed '\''s/;1$/;diagnosed/g'\'')" - #user added more actions while the diagnosis window was open - queue+=$'\''\n'\''"$new_lines" - fi - else - #user chose to retry action(s). Replace '1' exit codes with "diagnosed" to avoid repeated diagnosis - queue="$(echo "$queue" | sed '\''s/;1$/;diagnosed/g'\'')" - #and now add to queue the actions we want to retry. - queue+=$'\''\n'\''"$retry_apps" - fi - fi - - # reorder queue list to prioritize app refresh and file update actions - queue="$(reorder_list "$queue")" - - if [ ! -z "$new_lines" ] && [ "$sourced_updater" == 0 ] && grep -q "update\|refresh\|update-file" <<<"$new_lines" ;then #source updater if necessary - source "${DIRECTORY}/updater" source - sourced_updater=1 - fi - - #echo "current position in queue is ${current_line_num}" - #echo "queue is $queue" - - line="$(echo "$queue" | sed -n "${current_line_num}"p)" - #echo "Now handling request: $line" - - #indicate current action in current line of $queue - queue="$(echo "$queue" | sed "${current_line_num}s/$/;in-progress/")" - - #get first word of this line - the action. Subsequent words are the name of the app. - action="$(echo "$line" | awk -F'\'';'\'' '\''{print $1}'\'')" - app="$(echo "$line" | awk -F'\'';'\'' '\''{print $2}'\'')" - - #refresh the list in queue-viewer window as a background process - skip it if the list is still refreshing from last loop iteration; in game dev this is "dropped input" - if [ -z "$write_list_pid" ] || ! process_exists "$write_list_pid" ;then - write_list "$queue" & - write_list_pid=$! - - #secondary list-writing background process - kill it if it exists because write_list just sent a newer version of the list to yad - [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null - else - #if app1 is refreshed and app2 is then reinstalled, the list would only say app1 is bring refreshed for the entirety of app2s reinstallation, due to the process-skipping. - #launch a secondary background process that waits for $write_list_pid to finish - - #only allow one secondary background process to run; kill previous jobs and start a new one - [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null - (while process_exists $write_list_pid ;do sleep 1 ;done ; write_list "$queue") & - secondary_write_list_pid=$! - fi - - #run manage script for app installs, uninstalls, or updates. Avoid using it for file-updates and refreshes because that is out of the scope for manage script. - if [ "$action" == update-file ];then - #Set terminal title - echo -ne "\e]0;Updating ${app} file\a" - update_file "$app" - exitcode=$? - elif [ "$action" == refresh ];then - #Set terminal title - echo -ne "\e]0;Refreshing ${app}\a" - refresh_app "$app" - exitcode=$? - elif [ "$action" == update ];then #manage can handle this action, but avoid spawning subprocess - #Set terminal title - echo -ne "\e]0;Updating ${app}\a" - update_app "$app" - exitcode=$? - else - #Set terminal title - echo -ne "\e]0;${action^}ing ${app}\a" - "${DIRECTORY}/manage" "$action" "$app" - exitcode=$? - fi - - #record exit code in current line of $queue - [ "$exitcode" != 0 ] && exitcode=1 #for easier regex and sed lines, force non-zero exit codes to be 1 - queue="$(echo "$queue" | sed "${current_line_num}s/;in-progress$/;$exitcode/")" - - #one more line of $queue has been completed. - current_line_num=$((current_line_num+1)) - done - - #refresh the list in queue-viewer window for the final time with all actions complete - [ ! -z "$secondary_write_list_pid" ] && kill "$secondary_write_list_pid" 2>/dev/null #kill secondary list writer - wait $write_list_pid - write_list "$queue" - - #before exiting the loop, add a line to the queue-viewer window indicating that all items have completed. - echo "${DIRECTORY}/icons/none-1.png -${DIRECTORY}/icons/none-1.png -Done. -${DIRECTORY}/icons/none-1.png -" > "${DIRECTORY}/data/manage-daemon/yadlist" - - #all actions have been completed. Daemon has effectively stopped listening, so remove its pid file - rm -f "${DIRECTORY}/data/manage-daemon/pid" - - #close the queue-viewer window in a few seconds - (sleep 5; kill $yadpid 2>/dev/null) &' "Terminal Output" + manage_daemon_terminal_code' "Terminal Output" # Check if terminal-run failed to launch. GUI users don't see any terminal output if it fails (since there is no terminal open) so we need to prompt them with a GUI window if [ "$?" != 0 ]; then @@ -611,7 +625,7 @@ elif [ "$1" == 'multi-uninstall' ] || [ "$1" == 'multi-install' ];then for line in $queue ;do action="$(echo "$line" | awk -F ';' '{print $1}')" app="$(echo "$line" | awk -F ';' '{print $2}')" - + #run manage script for app installs, uninstalls, or updates. Avoid using it for file-updates and refreshes because that is out of the scope for manage script. if [ "$action" == update-file ];then #Set terminal title From 35e3f7287597d09dd9244f80d17fa8c5856f9d29 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Wed, 22 Jan 2025 18:44:30 -0600 Subject: [PATCH 05/14] add summary window with donation messages --- icons/botspot.png | Bin 0 -> 3664 bytes icons/theofficialgman.png | Bin 0 -> 6661 bytes manage | 76 ++++++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 icons/botspot.png create mode 100644 icons/theofficialgman.png diff --git a/icons/botspot.png b/icons/botspot.png new file mode 100644 index 0000000000000000000000000000000000000000..4d5bdf96da800f6d4437aa292268b97e22cd40bc GIT binary patch literal 3664 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%0Diz>g4yn)HG$ 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/dev/null #kill secondary list writer wait $write_list_pid @@ -497,11 +500,69 @@ Done. ${DIRECTORY}/icons/none-1.png " > "${DIRECTORY}/data/manage-daemon/yadlist" - #all actions have been completed. Daemon has effectively stopped listening, so remove its pid file - rm -f "${DIRECTORY}/data/manage-daemon/pid" - #close the queue-viewer window in a few seconds (sleep 5; kill $yadpid 2>/dev/null) & + + #display "all done" window where the queue was + export -f summary_window + setsid bash -c summary_window + } + + summary_window() { #given $queue, summarize what was done + export botspot_message='to Botspot (college student, Pi-Apps founder, kicked out, needs money)' + export gman_message='to theofficialgman (notable Pi-Apps contributor)' + summary_window_click_function() { + if [ "$5" == "$botspot_message" ];then + xdg-open 'https://github.com/sponsors/botspot' + elif [ "$5" == "$gman_message" ];then + xdg-open 'https://github.com/sponsors/theofficialgman' + fi + } + export -f summary_window_click_function + + (for line in $queue ;do + action="$(echo "$line" | awk -F';' '{print $1}')" + app="$(echo "$line" | awk -F';' '{print $2}')" + status="$(echo "$line" | awk -F';' '{print $3}')" + + if [ "$action" == update-file ] || [ "$action" == refresh ];then + continue #avoid flooding the summary window with less important completed actions + fi + + if [ "$status" == 0 ];then + #if status is 0, then action completed successfully. + echo "${DIRECTORY}/icons/success.png +${DIRECTORY}/icons/$action.png +$(echo "${action^}ed" | sed 's/Updateed/Updated/g') +${DIRECTORY}/apps/$app/icon-64.png +$app" + else + #if status is 1, then action completed unsuccessfully. + echo "${DIRECTORY}/icons/failure.png +${DIRECTORY}/icons/$action.png +Failed to $action +${DIRECTORY}/apps/$app/icon-64.png +$app" + fi + done + #display donate message at the end + echo "${DIRECTORY}/icons/none-24.png +${DIRECTORY}/icons/none-24.png +Donate +${DIRECTORY}/icons/botspot.png +$botspot_message +${DIRECTORY}/icons/none-24.png +${DIRECTORY}/icons/none-24.png +Donate +${DIRECTORY}/icons/theofficialgman.png +$gman_message" + ) | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Actions complete' \ + --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ + --wrap-width=190 --wrap-cols=5 --close-on-unfocus \ + --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ + --text="Thank you for using Pi-Apps! The following apps completed:" \ + --dclick-action=true --select-action="bash -c "\""summary_window_click_function %s"\""" \ + --button=' Close '!"${DIRECTORY}/icons/exit.png":0 >/dev/null & } if [ "$2" == source ];then @@ -565,14 +626,15 @@ ${DIRECTORY}/icons/none-1.png tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Monitor Progress' \ --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ - --dclick-action=true --select-action=true \ + --dclick-action=true --select-action=true --no-selection \ --no-buttons & yadpid=$! trap "kill $yadpid 2>/dev/null" EXIT "${DIRECTORY}/etc/terminal-run" ' - trap "sleep 5" EXIT + geometry2="'"$geometry2"'" + yadpid="'"$yadpid"'" export DIRECTORY="'"$DIRECTORY"'" source "${DIRECTORY}/api" generate_logo @@ -593,13 +655,13 @@ ${DIRECTORY}/icons/none-1.png fi fi - # if update refresh or update-file actions were run then update the .git folder + # if update, refresh, or update-file actions were run, then update the .git folder if [ "$sourced_updater" == 1 ]; then update_git fi #updates could have been run as part of the manage-daemon, so update the updatable-files and updatable-apps status files - "${DIRECTORY}/updater" set-status + "${DIRECTORY}/updater" set-status elif [ "$1" == 'multi-uninstall' ] || [ "$1" == 'multi-install' ];then From b6508e08d203bcd8bde792822c269d738a98baeb Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:49:33 -0600 Subject: [PATCH 06/14] tweak botspot donate message avoids falsely implying that I was kicked out of school --- manage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage b/manage index 24e6b3b52b..ca3e9063a1 100755 --- a/manage +++ b/manage @@ -509,7 +509,7 @@ ${DIRECTORY}/icons/none-1.png } summary_window() { #given $queue, summarize what was done - export botspot_message='to Botspot (college student, Pi-Apps founder, kicked out, needs money)' + export botspot_message='to Botspot (Pi-Apps founder, college student, nearly bankrupt)' export gman_message='to theofficialgman (notable Pi-Apps contributor)' summary_window_click_function() { if [ "$5" == "$botspot_message" ];then From 454efecc6869a2b076c14559c294b07fcf8b969e Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:24:45 -0600 Subject: [PATCH 07/14] update_app: always reinstall, will_reinstall: only if insalled Retains retrying failed updated apps, but avoids installing all app refreshes lol. --- api | 7 ++++--- updater | 60 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/api b/api index a85a141224..383b9eb0c6 100755 --- a/api +++ b/api @@ -1568,11 +1568,12 @@ will_reinstall() { #return 0 if $1 app will be reinstalled during an update, oth [ -z "$app" ] && error 'will_reinstall(): requires an argument' #exit immediately if app is not installed. - #if [ "$(app_status "$app")" != 'installed' ];then - # return 1 - #fi + if [ "$(app_status "$app")" != 'installed' ];then + return 1 + fi #it seems that the above code was added for speed alone https://github.com/Botspot/pi-apps/commit/d8bfc3f5fc9b42060bfbd68a11b24f66246d61bc #commenting it out allows retrying failed app update where uninstall succeeds but install fails + #edit: uncommented it again because all uninstalled app refreshes were now being installed #detect which installation script exists - both for local install and for update directory local local_scriptname="$(script_name_cpu "$app")" diff --git a/updater b/updater index 867b273810..acac633ae3 100755 --- a/updater +++ b/updater @@ -433,7 +433,7 @@ Refreshes the Pi-Apps details for apps that do not need to be reinstalled for th } -update_app() { #first arg is app name +update_app() { #given app name, uninstall it, update app folder, install it again local app="$1" [ -z "$app" ] && error "update_app(): no app specified!" status "Updating \e[1m${app}\e[0m\e[96m..." @@ -448,36 +448,30 @@ update_app() { #first arg is app name # the GUI updater executes check_repo with the "fast" option so it skips updating the pi-apps update folder and obtains any previously determined updatable apps and files # if we do not check for this then apps will be removed, the older version moved to trash, and then the new version will fail to copy over since it does not exist if [ -d "${DIRECTORY}/update/pi-apps/apps/${app}" ]; then - local installback=no - if will_reinstall "$app";then - installback=yes - status "$app's install script has been updated. Reinstalling $app..." - #uninstall it - if retrying an update with successful uninstall and failed install, don't uninstall again - if [ "$(app_status "$app")" != uninstalled ];then - "${DIRECTORY}/manage" uninstall "$app" update #report to the app uninstall script that this is an uninstall for the purpose of updating by passing "update" - fi - - #fix edge case: if app is installed but uninstall script doesn't exist somehow, then pretend app was uninstalled so that the reinstall later will happen noninteractively - if [ "$(app_status "$app")" == installed ];then - echo 'uninstalled' > "${DIRECTORY}/data/status/${app}" - fi + + status "$app's install script has been updated. Reinstalling $app..." + #uninstall it - if retrying an update with successful uninstall and failed install, don't uninstall again + if [ "$(app_status "$app")" != uninstalled ];then + "${DIRECTORY}/manage" uninstall "$app" update #report to the app uninstall script that this is an uninstall for the purpose of updating by passing "update" fi + #fix edge case: force-pretend app was uninstalled so that the reinstall later will happen noninteractively + echo 'uninstalled' > "${DIRECTORY}/data/status/${app}" + no_status=true refresh_app "$app" - failed=false - if [ "$installback" == 'yes' ];then - #install the app again - "${DIRECTORY}/manage" install "$app" update #report to the app install script that this is an install for the purpose of updating by passing "update" - if [ $? != 0 ]; then - failed=true - else - # click update link only if app is already installed and the update succeeded - shlink_link "$app" update & - fi + local failed=false + + #install the app again + "${DIRECTORY}/manage" install "$app" update #report to the app install script that this is an install for the purpose of updating by passing "update" + if [ $? != 0 ]; then + failed=true + else + # click update link only if app is already installed and the update succeeded + shlink_link "$app" update & fi else - failed=true + local failed=true fi if [ "$failed" == 'true' ]; then @@ -489,7 +483,7 @@ update_app() { #first arg is app name fi } -refresh_app() { #first arg is app name +refresh_app() { #update app folder only local app="$1" [ -z "$app" ] && error "refresh_app(): no app specified!" [ "$no_status" != true ] && status -n "Refreshing \e[1m${app}\e[0m\e[96m... " @@ -537,7 +531,11 @@ update_now_cli() { #input: updatable_files and updatable_apps variables done for app in $updatable_apps ;do - update_app "$app" + if will_reinstall "$app" ;then + update_app "$app" + else + refresh_app "$app" + fi done update_git @@ -551,7 +549,11 @@ update_now_gui_apps() { # deprecated function that is only here so old updater s local failed_apps="" local IFS=$'\n' for app in $updatable_apps ;do - update_app "$app" || failed_apps+="$app"$'\n' + if will_reinstall "$app" ;then + update_app "$app" || failed_apps+="$app"$'\n' + else + refresh_app "$app" || failed_apps+="$app"$'\n' + fi done #Set terminal title @@ -622,7 +624,7 @@ update_now_background() { #input: updatable_apps and updatable_files variables elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/install-${arch}" ] && [ ! -f "${DIRECTORY}/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/packages" ]; then continue # if app will be reinstalled then don't try to reinstall it in the background - elif [ "$(app_status "${app}")" == 'installed' ];then + elif will_reinstall "$app"; then continue # if app failed to install last time, show this app refresh to the user. elif [ "$(app_status "${app}")" == 'corrupted' ];then From 2102a55cde1515dccf51a8a3f1676609eb229313 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:33:20 -0600 Subject: [PATCH 08/14] bigger app names, fix for apps with space characters --- manage | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/manage b/manage index ca3e9063a1..1d0d351c42 100755 --- a/manage +++ b/manage @@ -509,6 +509,7 @@ ${DIRECTORY}/icons/none-1.png } summary_window() { #given $queue, summarize what was done + local IFS=$'\n' export botspot_message='to Botspot (Pi-Apps founder, college student, nearly bankrupt)' export gman_message='to theofficialgman (notable Pi-Apps contributor)' summary_window_click_function() { @@ -535,14 +536,14 @@ ${DIRECTORY}/icons/none-1.png ${DIRECTORY}/icons/$action.png $(echo "${action^}ed" | sed 's/Updateed/Updated/g') ${DIRECTORY}/apps/$app/icon-64.png -$app" +$app" else #if status is 1, then action completed unsuccessfully. echo "${DIRECTORY}/icons/failure.png ${DIRECTORY}/icons/$action.png Failed to $action ${DIRECTORY}/apps/$app/icon-64.png -$app" +$app" fi done #display donate message at the end From d65a27b9c05e15b8127306a1cc0fc12422cbec53 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Thu, 23 Jan 2025 17:39:15 -0600 Subject: [PATCH 09/14] skip summary window if nothing to show --- manage | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/manage b/manage index 1d0d351c42..a1f4def3c1 100755 --- a/manage +++ b/manage @@ -521,15 +521,16 @@ ${DIRECTORY}/icons/none-1.png } export -f summary_window_click_function + #avoid flooding the summary window with less important completed actions + queue="$(echo "$queue" | grep -v '^update-file;\|^refresh;')" + #skip summary window if it was just app and file refreshes + [ -z "$queue" ] && return 0 + (for line in $queue ;do action="$(echo "$line" | awk -F';' '{print $1}')" app="$(echo "$line" | awk -F';' '{print $2}')" status="$(echo "$line" | awk -F';' '{print $3}')" - if [ "$action" == update-file ] || [ "$action" == refresh ];then - continue #avoid flooding the summary window with less important completed actions - fi - if [ "$status" == 0 ];then #if status is 0, then action completed successfully. echo "${DIRECTORY}/icons/success.png @@ -557,7 +558,7 @@ ${DIRECTORY}/icons/none-24.png Donate ${DIRECTORY}/icons/theofficialgman.png $gman_message" - ) | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Actions complete' \ + ) | yad --class Pi-Apps --name "Pi-Apps" --width=480 --height=400 "$geometry2" --title='Actions complete' \ --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ --wrap-width=190 --wrap-cols=5 --close-on-unfocus \ --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ @@ -624,7 +625,7 @@ $gman_message" [ -z "$geometry2" ] && geometry2='--center' - tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" --width=330 --height=400 "$geometry2" --title='Monitor Progress' \ + tail -f --retry "${DIRECTORY}/data/manage-daemon/yadlist" 2>/dev/null | yad --class Pi-Apps --name "Pi-Apps" --width=480 --height=400 "$geometry2" --title='Monitor Progress' \ --list --tail --no-headers --column=:IMG --column=:IMG --column=Text --column=:IMG --column=Text \ --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ --dclick-action=true --select-action=true --no-selection \ From c5bdb87766710facf905bb125aedab11f8d6cf2c Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Thu, 23 Jan 2025 17:39:34 -0600 Subject: [PATCH 10/14] clarify new app updates if there are 5+ of them --- updater | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/updater b/updater index acac633ae3..b5141b2e7c 100755 --- a/updater +++ b/updater @@ -312,6 +312,7 @@ list_updates_gui() { #input: updatable_apps and updatable_files variables, outpu local LIST='' local app + local num_new_apps=0 #track how many newly available apps there are. If there are a lot, the user may be unchecking them, misunderstanding pi-apps updates local compressed_update='' for app in $updatable_apps ;do #generate a yad list for every updatable app # get app tooltip @@ -319,6 +320,7 @@ list_updates_gui() { #input: updatable_apps and updatable_files variables, outpu # if ${app} folder did not exist before and install-${arch}, install, or packages file is in the new update, then this is a "new app" # results in applications that only have support for a different architecture to show under the compressed update if [ ! -d "${DIRECTORY}/apps/${app}" ] && ( [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install-${arch}" ] || [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install" ] || [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/packages" ] ); then + num_new_apps=$((num_new_apps+1)) LIST+="TRUE ${DIRECTORY}/update/pi-apps/apps/${app}/icon-24.png $app (new app) @@ -326,6 +328,7 @@ refresh-app:$app $line"$'\n' # if install-${arch} is in the new update and it was not installable on this system before, then this is a "new app". elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install-${arch}" ] && [ ! -f "${DIRECTORY}/apps/${app}/install-${arch}" ] && [ ! -f "${DIRECTORY}/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/packages" ]; then + num_new_apps=$((num_new_apps+1)) LIST+="TRUE ${DIRECTORY}/update/pi-apps/apps/${app}/icon-24.png $app (new app) @@ -333,6 +336,7 @@ refresh-app:$app $line"$'\n' # similar to the above. if install script is in the new update and it was not installable on this system before, then this is a "new app". elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/install-${arch}" ] && [ ! -f "${DIRECTORY}/apps/${app}/install" ] && [ ! -f "${DIRECTORY}/apps/${app}/packages" ]; then + num_new_apps=$((num_new_apps+1)) LIST+="TRUE ${DIRECTORY}/update/pi-apps/apps/${app}/icon-24.png $app (new app) @@ -408,11 +412,18 @@ Refreshes the Pi-Apps details for apps that do not need to be reinstalled for th exit 0 fi + # if user has 5+ "new apps", they may be unchecking them all each time. Provide an explanatory message. + if [ $num_new_apps -ge 5 ];then + local update_hint_message="Pro tip: please leave the "\""new apps"\"" checked. This is just how Pi-Apps announces a new app that can be installed. Unless you have a very specific reason to keep an old app version, don't uncheck anything." + else + local update_hint_message="Uncheck an item to skip updating it." + fi + #Display a list of everything updatable output="$(echo "$LIST" | yad --class Pi-Apps --name "Pi-Apps" --center --title='Pi-Apps' \ --window-icon="${DIRECTORY}/icons/logo.png" --width=310 --height=300 \ --list --checklist --separator='\n' --print-column=4 --no-headers \ - --text="Updates available:"$'\n'"Uncheck an item to skip updating it." \ + --text="Updates available:"$'\n'"$update_hint_message" \ --column=:CHK --column=:IMG --column=Name --column=ID:HD --column=tip:HD --tooltip-column=5 \ --button='Cancel'!"${DIRECTORY}/icons/exit.png"!"Close without updating anything":1 \ --button='Update now'!"${DIRECTORY}/icons/download.png":0 \ From 07ffc0d4b93d75ad98840fd99bfaa5bb087980e9 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:41:03 -0600 Subject: [PATCH 11/14] donation click adds runonce hash for later use maybe --- manage | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/manage b/manage index a1f4def3c1..9ba081ebc6 100755 --- a/manage +++ b/manage @@ -514,9 +514,15 @@ ${DIRECTORY}/icons/none-1.png export gman_message='to theofficialgman (notable Pi-Apps contributor)' summary_window_click_function() { if [ "$5" == "$botspot_message" ];then - xdg-open 'https://github.com/sponsors/botspot' + xdg-open 'https://github.com/sponsors/botspot' & + + #remember that donation link was clicked - opts out of any popups introduced in the future + #"$(echo 'botspot donation click' | sha1sum | awk '{print $1}')" + if ! grep -q "8a780b08ac20332b897ecb399b25f4622bb31341" "${DIRECTORY}/data/runonce_hashes" ;then + echo "8a780b08ac20332b897ecb399b25f4622bb31341" >> "${DIRECTORY}/data/runonce_hashes" + fi elif [ "$5" == "$gman_message" ];then - xdg-open 'https://github.com/sponsors/theofficialgman' + xdg-open 'https://github.com/sponsors/theofficialgman' & fi } export -f summary_window_click_function From e7ae18a5cb75c9fc522ed832d00dfe03ae11a49c Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:45:49 -0600 Subject: [PATCH 12/14] document update_app better, remove unneeded edge case fix --- updater | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/updater b/updater index b5141b2e7c..8e5057dbad 100755 --- a/updater +++ b/updater @@ -444,7 +444,7 @@ Refreshes the Pi-Apps details for apps that do not need to be reinstalled for th } -update_app() { #given app name, uninstall it, update app folder, install it again +update_app() { #given app name, uninstall it, update app folder, install it again (not to be used for app refreshes!) local app="$1" [ -z "$app" ] && error "update_app(): no app specified!" status "Updating \e[1m${app}\e[0m\e[96m..." @@ -466,9 +466,7 @@ update_app() { #given app name, uninstall it, update app folder, install it agai "${DIRECTORY}/manage" uninstall "$app" update #report to the app uninstall script that this is an uninstall for the purpose of updating by passing "update" fi - #fix edge case: force-pretend app was uninstalled so that the reinstall later will happen noninteractively - echo 'uninstalled' > "${DIRECTORY}/data/status/${app}" - + #copy new version of the app folder to main pi-apps directory no_status=true refresh_app "$app" local failed=false From 0e8a591732867bff9a775e474bc4eae9c0d94e32 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:50:24 -0600 Subject: [PATCH 13/14] improve terminal_manage_multi documentation --- api | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api b/api index 383b9eb0c6..f6ce6b31a8 100755 --- a/api +++ b/api @@ -1081,8 +1081,8 @@ terminal_manage() { # wrapper for the original terminal_manage function to termi terminal_manage_multi "$action $app" } -terminal_manage_multi() { #function to install/uninstall/update/refresh multiple apps - refreshes the app list if applicable - local queue="$1" #one or multiple actions and app names +terminal_manage_multi() { #function to install/uninstall/update/refresh apps or refresh-file files, one per line - refreshes the gui app list if applicable + local queue="$1" #one action per line, in the format "$action $app" or "update-file $file" #To prevent multiple simultaneous manage instances, use the 'daemon' mode. This will create a queue of actions that are executed concurrently. #The first daemon instance is the 'master' process, which opens a terminal. Subsequent processes will add the action to the queue and then exit. From 48b2e56714e57baccb7bb58d6509188204ca2519 Mon Sep 17 00:00:00 2001 From: Botspot <54716352+Botspot@users.noreply.github.com> Date: Sat, 25 Jan 2025 12:33:36 -0600 Subject: [PATCH 14/14] update daemon pid to that of the terminal --- manage | 2 ++ 1 file changed, 2 insertions(+) diff --git a/manage b/manage index 9ba081ebc6..fc7b7d1f2d 100755 --- a/manage +++ b/manage @@ -647,6 +647,8 @@ $gman_message" source "${DIRECTORY}/api" generate_logo + #update daemon pid to that of the terminal, in case original manage script is killed somehow + echo $$ > "${DIRECTORY}/data/manage-daemon/pid" source "${DIRECTORY}/manage" daemon source manage_daemon_terminal_code' "Terminal Output"