You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Bash
		
	
			
		
		
	
	
			430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Bash
		
	
#!/bin/bash
 | 
						|
 | 
						|
#$1 is an action, like install
 | 
						|
#$2 is app name, like Arduino
 | 
						|
 | 
						|
DIRECTORY="$(readlink -f "$(dirname "$0")")"
 | 
						|
 | 
						|
function error {
 | 
						|
  echo -e "\e[91m$1\e[39m"
 | 
						|
  exit 1
 | 
						|
}
 | 
						|
 | 
						|
if [ -z "$1" ];then
 | 
						|
  error "You need to specify an operation, and in most cases, which app to operate on."
 | 
						|
fi
 | 
						|
 | 
						|
source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api"
 | 
						|
 | 
						|
mkdir -p "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status" "${DIRECTORY}/logs"
 | 
						|
#remove week-old logfiles
 | 
						|
find "$DIRECTORY/logs" -type f -mtime +7 -exec rm -f {} \; &>/dev/null &
 | 
						|
 | 
						|
#determine if host system is 64 bit arm64 or 32 bit armhf
 | 
						|
if [ ! -z "$(file "$(readlink -f "/sbin/init")" | grep 64)" ];then
 | 
						|
  arch=64
 | 
						|
elif [ ! -z "$(file "$(readlink -f "/sbin/init")" | grep 32)" ];then
 | 
						|
  arch=32
 | 
						|
else
 | 
						|
  error "Failed to detect OS CPU architecture! Something is very wrong."
 | 
						|
fi
 | 
						|
 | 
						|
#Ensure running arm processor
 | 
						|
if uname -m | grep -q 'x86' ;then
 | 
						|
  error "Pi-Apps is not not supported on x86 processors."
 | 
						|
fi
 | 
						|
#check for internet connection
 | 
						|
if ! ping -c 1 github.com &>/dev/null ;then
 | 
						|
  error "No internet connection!\ngithub.com failed to respond.\nErrors: $(ping -c 1 github.com 2>&1)"
 | 
						|
fi
 | 
						|
 | 
						|
dirhash() {
 | 
						|
  #echo "Hashing this dir: $1" 1>&2
 | 
						|
  
 | 
						|
  if [ -d "$1" ];then
 | 
						|
    #-------- hash every file in the folder ---------------------------------------------------- list all filenames ------------------- hash all that again
 | 
						|
    hash="$(echo -e "$(find "$1" -type f -print0 | xargs -0 sha1sum | awk '{print $1}')$(find "$1" -type f -exec basename {} \;)" | sha1sum | awk '{print $1}')"
 | 
						|
  else
 | 
						|
    hash=''
 | 
						|
    #echo "dirhash(): Folder '$1' does not exist" 1>&2
 | 
						|
  fi
 | 
						|
  echo "$hash"
 | 
						|
}
 | 
						|
 | 
						|
if [ "$1" == 'multi-install' ];then
 | 
						|
  
 | 
						|
  failed_apps=''
 | 
						|
  
 | 
						|
  IFS=$'\n'
 | 
						|
  for app in $2
 | 
						|
  do
 | 
						|
    "${DIRECTORY}/manage" install "$app"
 | 
						|
    if [ $? != 0 ];then
 | 
						|
      #this app failed to install - add it to the list of failed apps
 | 
						|
      failed_apps="$failed_apps
 | 
						|
$app"
 | 
						|
    fi
 | 
						|
  done
 | 
						|
  app_results="${app_results:1}" #remove first blank newline
 | 
						|
  
 | 
						|
  for app in $failed_apps ;do
 | 
						|
    logfile="$(ls -dt "${DIRECTORY}/logs"/* | grep '\-'"${app}"'\.log' -m 1)" #sort logfiles by modification date, get the most recent one for the current app
 | 
						|
    
 | 
						|
    #if logfile detected, exists, and is not empty, ask permission to send error report
 | 
						|
    if [ ! -z "$logfile" ] && [ -f "$logfile" ] && [ -s "$logfile" ];then
 | 
						|
      send_error_report_gui "$logfile" "<b>$app</b> failed to install."
 | 
						|
    fi
 | 
						|
  done
 | 
						|
  if [ ! -z "$failed_apps" ];then
 | 
						|
    exit 1
 | 
						|
  fi
 | 
						|
  
 | 
						|
elif [ "$1" == 'multi-uninstall' ];then
 | 
						|
  failed_apps=''
 | 
						|
  
 | 
						|
  IFS=$'\n'
 | 
						|
  for app in $2
 | 
						|
  do
 | 
						|
    "${DIRECTORY}/manage" uninstall "$app"
 | 
						|
    if [ $? != 0 ];then
 | 
						|
      #this app failed to install - add it to the list of failed apps
 | 
						|
      failed_apps="$failed_apps
 | 
						|
$app"
 | 
						|
    fi
 | 
						|
  done
 | 
						|
  app_results="${app_results:1}" #remove first blank newline
 | 
						|
  
 | 
						|
  for app in $failed_apps ;do
 | 
						|
    logfile="$(ls -dt "${DIRECTORY}/logs"/* | grep '\-'"${app}"'\.log' -m 1)" #sort logfiles by modification date, get the most recent one for the current app
 | 
						|
    
 | 
						|
    #if logfile detected, exists, and is not empty, ask permission to send error report
 | 
						|
    if [ ! -z "$logfile" ] && [ -f "$logfile" ] && [ -s "$logfile" ];then
 | 
						|
      send_error_report_gui "$logfile" "<b>$app</b> failed to uninstall."
 | 
						|
    fi
 | 
						|
  done
 | 
						|
  if [ ! -z "$failed_apps" ];then
 | 
						|
    exit 1
 | 
						|
  fi
 | 
						|
  
 | 
						|
elif [ "$1" == 'install-if-not-installed' ];then
 | 
						|
  
 | 
						|
  #if not installed
 | 
						|
  if [ "$(app_status "$2")" != installed ];then
 | 
						|
    #install it
 | 
						|
    "${DIRECTORY}/manage" install "$2" || exit 1
 | 
						|
  fi
 | 
						|
  
 | 
						|
elif [ "$1" == 'install' ];then
 | 
						|
  #INSTALL
 | 
						|
  #for this operation, a program name must be specified.
 | 
						|
  app="$2"
 | 
						|
  if [ -z "$app" ];then
 | 
						|
    error "For this operation, you must specify which app to operate on."
 | 
						|
  elif [ ! -d "${DIRECTORY}/apps/$app" ];then
 | 
						|
    error "${DIRECTORY}/apps/$app does not exist!"
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #ensure not a disabled app
 | 
						|
  if [ -f "${DIRECTORY}/data/status/${app}" ] && [ "$(app_status "${app}")" == 'disabled' ];then
 | 
						|
    echo -e "\e[93mNot installing the $app app. IT IS DISABLED.\e[39m"
 | 
						|
    sleep 1
 | 
						|
    echo 'Waiting 5 seconds...'
 | 
						|
    sleep 5
 | 
						|
    exit 0
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #if already installed then ask for confirmation
 | 
						|
  if [ "$(app_status "${app}")" == 'installed' ];then
 | 
						|
    yad --text="$app is already installed. Are you sure you want to install it again?" \
 | 
						|
    --text-align=center --center --title='Quick question' --window-icon="${DIRECTORY}/icons/logo.png" \
 | 
						|
    --button=No!"${DIRECTORY}/icons/exit.png":1 --button=Yes!"${DIRECTORY}/icons/check.png":0 || exit 0
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #analytics
 | 
						|
  "${DIRECTORY}/etc/bitlylink" "$app" install &
 | 
						|
  
 | 
						|
  #determine which script to run
 | 
						|
  scriptname="$(script_name_cpu "$app")" #will be install, install-32, or install-64
 | 
						|
  installscript="${DIRECTORY}/apps/${app}/${scriptname}"
 | 
						|
  [ -z "$scriptname" ] && error "It appears $app does not have an install-${arch} script suitable for your ${arch}-bit OS."
 | 
						|
  
 | 
						|
  #determine path for log file to be created
 | 
						|
  logfile="${DIRECTORY}/logs/install-incomplete-${app}.log"
 | 
						|
  if [ -f "$logfile" ] || [ -f "$(echo "$logfile" | sed 's+-incomplete-+-success-+g')" ] || [ -f "$(echo "$logfile" | sed 's+-incomplete-+-fail-+g')" ];then
 | 
						|
    #append a number to logfile's file-extension if the original filename already exists
 | 
						|
    i=1
 | 
						|
    while true;do
 | 
						|
      #if variable $i is 2, then example newlogfile value: /path/to/install-Discord.log2
 | 
						|
      newlogfile="$logfile$i"
 | 
						|
      if [ ! -f "$newlogfile" ] && [ ! -f "$(echo "$newlogfile" | sed 's+/-incomplete-+-success-+g')" ] && [ ! -f "$(echo "$newlogfile" | sed 's+-incomplete-+-fail-+g')" ];then
 | 
						|
        logfile="${newlogfile}"
 | 
						|
        break
 | 
						|
      fi
 | 
						|
      i=$((i+1))
 | 
						|
    done
 | 
						|
  fi
 | 
						|
  #for piping to tee, the install script's exit code is preserved by enabling the pipefail bash builtin
 | 
						|
  set -o pipefail
 | 
						|
  
 | 
						|
  chmod u+x "$installscript"
 | 
						|
  
 | 
						|
  echo -e "\e[96mInstalling $app with $scriptname script\e[39m" | tee -a "$logfile"
 | 
						|
  cd $HOME
 | 
						|
  echo 'corrupted' > "${DIRECTORY}/data/status/${app}"
 | 
						|
  if nice "$installscript" 2>&1 | tee -a "$logfile" ; then
 | 
						|
    echo 'installed' > "${DIRECTORY}/data/status/${app}"
 | 
						|
    echo -e "\n\e[42m\e[30mInstalled ${app} successfully.\e[39m\e[49m" | tee -a "$logfile"
 | 
						|
    
 | 
						|
    format_log_file "$logfile" #remove escape sequences from logfile
 | 
						|
    mv "$logfile" "$(echo "$logfile" | sed 's+-incomplete-+-success-+g')" #
 | 
						|
    exit 0
 | 
						|
  else
 | 
						|
    echo -e "\n\e[91mFailed to install ${app} with $scriptname script"\!"\e[39m
 | 
						|
\e[40m\e[93m\e[5m▲\e[25m\e[39m \e[49m\e[93mNeed help? Copy the \e[1mENTIRE\e[0m\e[49m\e[93m terminal output or take a screenshot.
 | 
						|
Please ask on Github: \e[94m\e[4mhttps://github.com/Botspot/pi-apps/issues/new/choose\e[24m\e[93m
 | 
						|
Or on Discord: \e[94m\e[4mhttps://discord.gg/RXSTvaUvuu\e[24m\e[39m" | tee -a "$logfile"
 | 
						|
    
 | 
						|
    format_log_file "$logfile" #remove escape sequences from logfile
 | 
						|
    mv "$logfile" "$(echo "$logfile" | sed 's+-incomplete-+-fail-+g')"
 | 
						|
    exit 1
 | 
						|
  fi
 | 
						|
  
 | 
						|
elif [ "$1" == 'uninstall' ];then
 | 
						|
  #UNINSTALL
 | 
						|
  #for this operation, a program name must be specified.
 | 
						|
  app="$2"
 | 
						|
  if [ -z "$app" ];then
 | 
						|
    error "For this operation, you must specify which app to operate on."
 | 
						|
  elif [ ! -d "${DIRECTORY}/apps/$app" ];then
 | 
						|
    error "${DIRECTORY}/apps/$app does not exist!"
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #if already uninstalled then ask for confirmation
 | 
						|
  if [ "$(app_status "${app}")" == 'uninstalled' ];then
 | 
						|
    yad --text="$app is already uninstalled. Are you sure you want to uninstall it again?" \
 | 
						|
    --text-align=center --center --title='Quick question' --window-icon="${DIRECTORY}/icons/logo.png" \
 | 
						|
    --button=No!"${DIRECTORY}/icons/exit.png":1 --button=Yes!"${DIRECTORY}/icons/check.png":0 || exit 0
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #analytics
 | 
						|
  "${DIRECTORY}/etc/bitlylink" "$app" uninstall &
 | 
						|
  
 | 
						|
  #determine path for log file to be created
 | 
						|
  logfile="${DIRECTORY}/logs/uninstall-incomplete-${app}.log"
 | 
						|
  if [ -f "$logfile" ] || [ -f "$(echo "$logfile" | sed 's+/-incomplete-+/-success-+g')" ] || [ -f "$(echo "$logfile" | sed 's+/-incomplete-+/-fail-+g')" ];then
 | 
						|
    #append a number to logfile's file-extension if the original filename already exists
 | 
						|
    i=1
 | 
						|
    while true;do
 | 
						|
      #if variable $i is 2, then example newlogfile value: /path/to/install-Discord.log2
 | 
						|
      newlogfile="$logfile$i"
 | 
						|
      if [ ! -f "$newlogfile" ] && [ ! -f "$(echo "$newlogfile" | sed 's+/-incomplete-+/-success-+g')" ] && [ ! -f "$(echo "$newlogfile" | sed 's+/-incomplete-+/-fail-+g')" ];then
 | 
						|
        logfile="${newlogfile}"
 | 
						|
        break
 | 
						|
      fi
 | 
						|
      i=$((i+1))
 | 
						|
    done
 | 
						|
  fi
 | 
						|
  #for piping to tee, the install script's exit code is preserved by enabling the pipefail bash builtin
 | 
						|
  set -o pipefail
 | 
						|
  
 | 
						|
  chmod u+x "${DIRECTORY}/apps/${app}/uninstall"
 | 
						|
  
 | 
						|
  echo -e "\e[96mUninstalling $app\e[39m" | tee -a "$logfile"
 | 
						|
  cd $HOME
 | 
						|
  echo 'corrupted' > "${DIRECTORY}/data/status/${app}"
 | 
						|
  if nice "${DIRECTORY}/apps/${app}/uninstall" 2>&1 | tee -a "$logfile"; then
 | 
						|
    echo 'uninstalled' > "${DIRECTORY}/data/status/${app}"
 | 
						|
    echo -e "\n\e[42m\e[30mUninstalled ${app} successfully.\e[39m\e[49m" | tee -a "$logfile"
 | 
						|
    format_log_file "$logfile" #remove escape sequences from logfile
 | 
						|
    mv "$logfile" "$(echo "$logfile" | sed 's+-incomplete-+-success-+g')"
 | 
						|
    exit 0
 | 
						|
  else
 | 
						|
    echo -e "\n\e[91mFailed to uninstall ${app}"\!"\e[39m
 | 
						|
\e[40m\e[93m\e[5m▲\e[25m\e[39m \e[49m\e[93mNeed help? Copy the \e[1mENTIRE\e[0m\e[49m\e[93m terminal output or take a screenshot.
 | 
						|
Please ask on Github: \e[94m\e[4mhttps://github.com/Botspot/pi-apps/issues/new/choose\e[24m\e[93m
 | 
						|
Or on Discord: \e[94m\e[4mhttps://discord.gg/RXSTvaUvuu\e[24m\e[39m" | tee -a "$logfile"
 | 
						|
    format_log_file "$logfile" #remove escape sequences from logfile
 | 
						|
    mv "$logfile" "$(echo "$logfile" | sed 's+-incomplete-+-fail-+g')"
 | 
						|
    exit 1
 | 
						|
  fi
 | 
						|
  
 | 
						|
elif [ "$1" == 'update' ];then
 | 
						|
  #UPDATE
 | 
						|
  #for this operation, a program name must be specified.
 | 
						|
  app="$2"
 | 
						|
  if [ -z "$app" ];then
 | 
						|
    error "For this operation, you must specify which app to operate on."
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #HIDDEN FEATURE - if $3 equals nofetch, then don't download github repo. Useful for updating multiple apps at maximum speed
 | 
						|
  if [ "$3" == 'nofetch' ] && [ -d "${DIRECTORY}/update" ];then
 | 
						|
    true
 | 
						|
  else
 | 
						|
    rm -rf "${DIRECTORY}/update" && mkdir "${DIRECTORY}/update" && cd "${DIRECTORY}/update" || error "failed to enter the update directory!"
 | 
						|
    git clone --depth=1 "$(cat "${DIRECTORY}/etc/git_url")" || error "failed to clone repository!"
 | 
						|
  fi
 | 
						|
  
 | 
						|
  newhash="$(dirhash "${DIRECTORY}/update/pi-apps/apps/${app}")"
 | 
						|
  oldhash="$(dirhash "${DIRECTORY}/apps/${app}")"
 | 
						|
  
 | 
						|
  #detect which installation script exists and get the hash for that one
 | 
						|
  scriptname="$(script_name_cpu "$app")"
 | 
						|
  [ $? == 1 ] && exit 1
 | 
						|
  
 | 
						|
  newinstallhash=$(sha1sum "${DIRECTORY}/update/pi-apps/apps/${app}/${scriptname}" 2>/dev/null | awk '{print $1}')
 | 
						|
  oldinstallhash=$(sha1sum "${DIRECTORY}/apps/${app}/${scriptname}" 2>/dev/null | awk '{print $1}')
 | 
						|
  
 | 
						|
  #echo -e "newinstallhash: $newinstallhash\noldinstallhash: $oldinstallhash"
 | 
						|
  #echo -e "newhash: $newhash\noldhash: $oldhash"
 | 
						|
  
 | 
						|
  if [ "$newhash" == "$oldhash" ];then
 | 
						|
    echo "$app is identical to the online version. Nothing to do!"
 | 
						|
    exit 0
 | 
						|
  fi
 | 
						|
  #else
 | 
						|
  echo "$app is not identical to the online version."
 | 
						|
  installback=no
 | 
						|
  
 | 
						|
  #if install script was changed                                                    #if installed already
 | 
						|
  if [ "$newinstallhash" != "$oldinstallhash" ] && [ "$(app_status "${app}")" == 'installed' ];then
 | 
						|
    installback=yes
 | 
						|
    echo "$app's install script has been updated. Reinstalling $app..."
 | 
						|
    #uninstall it using a recursive script instance
 | 
						|
    "${DIRECTORY}/manage" uninstall "$app"
 | 
						|
    
 | 
						|
    #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
 | 
						|
  
 | 
						|
  #move old program to trash
 | 
						|
  gio trash "${DIRECTORY}/apps/${app}" 2>/dev/null
 | 
						|
  #failsafe
 | 
						|
  [ -d "${DIRECTORY}/apps/${app}" ] && rm -rf "${DIRECTORY}/apps/${app}"
 | 
						|
  
 | 
						|
  #copy new version from update/ to apps/
 | 
						|
  cp -rf "${DIRECTORY}/update/pi-apps/apps/${app}" "${DIRECTORY}/apps/${app}"
 | 
						|
  
 | 
						|
  if [ "$installback" == 'yes' ];then
 | 
						|
    echo "$app was originally installed before updating. Reinstalling the new version now."
 | 
						|
    #install it using a recursive script instance
 | 
						|
    "${DIRECTORY}/manage" install "$app"
 | 
						|
  fi
 | 
						|
  echo -e "\e[92m${app} was updated successfully.\e[39m"
 | 
						|
  
 | 
						|
elif [ "$1" == 'check-all' ];then
 | 
						|
  #CHECK-ALL
 | 
						|
  #for this operation, a program name cannot be specified.
 | 
						|
  
 | 
						|
  #hidden flags
 | 
						|
  installedonly=0
 | 
						|
  if [ "$2" == 'installedonly' ];then
 | 
						|
    # If $2 is 'installedonly', then only check for updates for those apps that are installed
 | 
						|
    installedonly=1
 | 
						|
    
 | 
						|
  elif [ "$2" == 'nogenerate' ];then
 | 
						|
    # If $2 is 'nogenerate', then don't hash anything or git-clone anything. Simply reads out data found in data/update-status folder in the same app-per-newline format.
 | 
						|
    echo -e "\e[97mThese apps can be updated:" 1>&2
 | 
						|
    echo "${updatable}"
 | 
						|
    IFS=$'\n'
 | 
						|
    for app in $(list_apps all);do
 | 
						|
      
 | 
						|
      updatestatus="$(cat "${DIRECTORY}/data/update-status/${app}" 2>/dev/null)"
 | 
						|
      if [ "$updatestatus" == 'new' ] || [ "$updatestatus" == 'updatable' ];then
 | 
						|
        #if current app's update-status is 'new' or 'updatable', then echo it.
 | 
						|
        echo "$app"
 | 
						|
      fi
 | 
						|
      
 | 
						|
    done
 | 
						|
   exit 0 #the lines above have displayed a list of apps already.
 | 
						|
   
 | 
						|
  fi #end of checking for hidden flags
 | 
						|
  
 | 
						|
  #if the updater script exists in update folder, then just git pull to save time
 | 
						|
  if [ -f "${DIRECTORY}/update/pi-apps/updater" ];then
 | 
						|
    cd "${DIRECTORY}/update/pi-apps"
 | 
						|
    echo -n "The 'git pull' command says: " 1>&2
 | 
						|
    git pull 1>&2 || rm -rf "${DIRECTORY}/update"
 | 
						|
  fi
 | 
						|
  #re-check and if updater script does not exist then do a git clone
 | 
						|
  if [ ! -f "${DIRECTORY}/update/pi-apps/updater" ];then
 | 
						|
    rm -rf "${DIRECTORY}/update"
 | 
						|
    mkdir -p "${DIRECTORY}/update" && cd "${DIRECTORY}/update" || error "failed to enter the update directory!"
 | 
						|
    git clone --depth=1 "$(cat "${DIRECTORY}/etc/git_url")" 1>&2|| error "failed to clone repository to the update directory!"
 | 
						|
  fi
 | 
						|
  
 | 
						|
  if [ $installedonly == 1 ];then
 | 
						|
    #installedonly flag enabled. Remove apps that are uninstalled, disabled, or corrupted
 | 
						|
    applist="$(list_apps installed)"
 | 
						|
  else
 | 
						|
    #installedonly flag disabled, so use entire combined list of apps, both local and online
 | 
						|
    applist="$(list_apps all)"
 | 
						|
  fi
 | 
						|
  
 | 
						|
  #echo "App list: $applist" 1>&2
 | 
						|
  
 | 
						|
  updatable=''
 | 
						|
  IFS=$'\n'
 | 
						|
  for app in $applist
 | 
						|
  do
 | 
						|
    #echo "app: $app"
 | 
						|
    newhash="$(dirhash "${DIRECTORY}/update/pi-apps/apps/${app}")" #folder will not exist if local app
 | 
						|
    oldhash="$(dirhash "${DIRECTORY}/apps/${app}")" #folder will not exist if new online app
 | 
						|
    #echo -e "newhash: $newhash\noldhash: $oldhash" 1>&2
 | 
						|
    
 | 
						|
    if [ "$newhash" == "$oldhash" ];then
 | 
						|
      #echo -e "${app} is identical\e[90m to the online version. Nothing to do!\e[39m" 1>&2
 | 
						|
      echo 'latest' > "${DIRECTORY}/data/update-status/${app}"
 | 
						|
    else
 | 
						|
      if [ ! -d "${DIRECTORY}/apps/${app}" ];then
 | 
						|
        echo -e "\e[97m${app} does not exist locally.\e[39m Adding to updatable list." 1>&2
 | 
						|
        echo 'new' > "${DIRECTORY}/data/update-status/${app}"
 | 
						|
        #in this case, add to updatable list
 | 
						|
        updatable="${updatable}
 | 
						|
${app}"
 | 
						|
      elif [ ! -d "${DIRECTORY}/update/pi-apps/apps/${app}" ];then
 | 
						|
        #echo -e "\e[97m${app} only exists locally.\e[39m Will not add to updatable list." 1>&2
 | 
						|
        echo 'local' > "${DIRECTORY}/data/update-status/${app}"
 | 
						|
        #in this case, do not add to updatable list
 | 
						|
      else
 | 
						|
        echo -e "\e[97m${app} exists in both locations, but online version is newer\e[39m. Adding to updatable list." 1>&2
 | 
						|
        echo 'updatable' > "${DIRECTORY}/data/update-status/${app}"
 | 
						|
        #in this case, add to updatable list
 | 
						|
        updatable="${updatable}
 | 
						|
${app}"
 | 
						|
      fi
 | 
						|
      
 | 
						|
    fi
 | 
						|
  done 
 | 
						|
  
 | 
						|
  #remove initial newline character
 | 
						|
  updatable="${updatable:1}"
 | 
						|
  
 | 
						|
  if [ -z "$updatable" ];then
 | 
						|
    updatable='.'
 | 
						|
  fi
 | 
						|
  
 | 
						|
  echo -e "\e[97mThese apps can be updated:" 1>&2
 | 
						|
  echo "${updatable}"
 | 
						|
elif [ "$1" == 'update-all' ];then
 | 
						|
  #UPDATE-ALL
 | 
						|
  #for this operation, a program name cannot be specified.
 | 
						|
  IFS=$'\n'
 | 
						|
  updatable="$("${DIRECTORY}/manage" check-all)"
 | 
						|
  if [ "$updatable" == '.' ];then
 | 
						|
    updatable=''
 | 
						|
  fi
 | 
						|
  echo "Updatable: ${updatable}EOU"
 | 
						|
  for updateapp in $updatable
 | 
						|
  do
 | 
						|
    echo "updating $updateapp"
 | 
						|
    #update it using a recursive script instance
 | 
						|
    echo "${DIRECTORY}/manage update $updateapp"
 | 
						|
    "${DIRECTORY}/manage" update "$updateapp" || exit 1
 | 
						|
  done
 | 
						|
  echo -e '\e[92mOperation completed successfully!\e[39m'
 | 
						|
else
 | 
						|
  error "Did not understand $1. Allowed values: 'install', 'multi-install', 'install-if-not-installed', 'uninstall', 'multi-uninstall', 'update','update-all', or 'check-all'."
 | 
						|
fi
 |