|
|
|
#!/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
|
|
|
|
|
|
|
|
mkdir -p "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status"
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
dirhash() {
|
|
|
|
#find "${DIRECTORY}/update/pi-apps/apps/${2}" -type f -print0
|
|
|
|
#echo "Hashing this dir: $1" 1>&2
|
|
|
|
#------ hash every file in the folder ---------------- and add to it the filesystem list ------ hash it 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}')"
|
|
|
|
echo "$hash"
|
|
|
|
}
|
|
|
|
if [ "$1" == 'multi-install' ];then
|
|
|
|
failed=0
|
|
|
|
PREIFS="$IFS"
|
|
|
|
IFS=$'\n'
|
|
|
|
for app in $2
|
|
|
|
do
|
|
|
|
"${DIRECTORY}/manage" install "$app"
|
|
|
|
if [ $? != 0 ];then
|
|
|
|
failed=1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
IFS="$PREIFS"
|
|
|
|
if [ $failed == 1 ];then
|
|
|
|
exit 1
|
|
|
|
elif [ "$(ls "${DIRECTORY}/data/status" | wc -l)" -ge 5 ] && [ "$(($(date --utc --date '' +%s)/86400-30))" -ge "$(cat "${DIRECTORY}/data/last-donate-ask" 2>/dev/null || echo "0")" ];then
|
|
|
|
donatebox() {
|
|
|
|
TEXT="$(wget -qO- https://raw.githubusercontent.com/Botspot/pi-apps-announcements/main/donate_message)"
|
|
|
|
if [ -z "$TEXT" ];then
|
|
|
|
TEXT=" <b>Pi-Apps depends on you!</b>
|
|
|
|
|
|
|
|
I (Botspot) have spent <b>over 300 hours</b> programming Pi-Apps.
|
|
|
|
Without financial support, I can't continue developing Pi-Apps as much as I have been. :(
|
|
|
|
If every Pi-Apps user pitched in a mere <i>25 cents</i>, I could work on open-source development full-time.
|
|
|
|
|
|
|
|
If Pi-Apps has saved you time & effort, please consider donating. Any amount helps.
|
|
|
|
"
|
|
|
|
fi
|
|
|
|
yad --title="Donations, anyone?" --center \
|
|
|
|
--window-icon="${DIRECTORY}/icons/logo.png" \
|
|
|
|
--text="$(echo -e "$TEXT")" \
|
|
|
|
--button='Support Pi-Apps'!"${DIRECTORY}/icons/paypal.png":0 \
|
|
|
|
--button='No thanks'!"${DIRECTORY}/icons/exit.png"!"I respect your decision.
|
|
|
|
Pi-Apps will always be free, but if everyone clicks this button, it won"\'"t be maintained forever.":1
|
|
|
|
button=$?
|
|
|
|
|
|
|
|
if [ $button == 0 ];then
|
|
|
|
#open donation page if button 0 clicked
|
|
|
|
#x-www-browser 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=V6W8WM4GN8AJ2&item_name=Pi-Apps+development¤cy_code=USD'
|
|
|
|
x-www-browser 'https://paypal.me/josephmarchand'
|
|
|
|
fi
|
|
|
|
#don't ask again for 30 days, no matter what button clicked
|
|
|
|
echo "$(($(date --utc --date '' +%s)/86400))" > "${DIRECTORY}/data/last-donate-ask"
|
|
|
|
}
|
|
|
|
export -f donatebox
|
|
|
|
export DIRECTORY
|
|
|
|
setsid bash -c donatebox
|
|
|
|
fi
|
|
|
|
elif [ "$1" == 'multi-uninstall' ];then
|
|
|
|
failed=0
|
|
|
|
PREIFS="$IFS"
|
|
|
|
IFS=$'\n'
|
|
|
|
for app in $2
|
|
|
|
do
|
|
|
|
"${DIRECTORY}/manage" uninstall "$app"
|
|
|
|
if [ $? != 0 ];then
|
|
|
|
failed=1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
IFS="$PREIFS"
|
|
|
|
if [ $failed == 1 ];then
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
elif [ "$1" == 'install-if-not-installed' ];then
|
|
|
|
|
|
|
|
#if not installed
|
|
|
|
if [ ! -f "${DIRECTORY}/data/status/$2" ] || [ "$(cat "${DIRECTORY}/data/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
|
|
|
|
|
|
|
|
#if already installed then ask for confirmation
|
|
|
|
if [ "$(cat "${DIRECTORY}/data/status/${app}" 2>/dev/null)" == '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
|
|
|
|
if [ -f "${DIRECTORY}/apps/${app}/install-32" ] && [ $arch == 32 ];then
|
|
|
|
installscript="${DIRECTORY}/apps/${app}/install-32"
|
|
|
|
scriptname='install-32'
|
|
|
|
elif [ -f "${DIRECTORY}/apps/${app}/install-64" ] && [ $arch == 64 ];then
|
|
|
|
installscript="${DIRECTORY}/apps/${app}/install-64"
|
|
|
|
scriptname='install-64'
|
|
|
|
elif [ -f "${DIRECTORY}/apps/${app}/install" ];then
|
|
|
|
installscript="${DIRECTORY}/apps/${app}/install"
|
|
|
|
scriptname='install'
|
|
|
|
else
|
|
|
|
error "It appears $app does not have an install-${arch} script suitable for your ${arch}-bit OS."
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo -e "\e[96mInstalling $app with $scriptname script\e[39m"
|
|
|
|
cd $HOME
|
|
|
|
echo 'corrupted' > "${DIRECTORY}/data/status/${app}"
|
|
|
|
if nice "$installscript" ; then
|
|
|
|
echo 'installed' > "${DIRECTORY}/data/status/${app}"
|
|
|
|
echo -e "\n\e[42m\e[30mInstalled ${app} successfully.\e[39m\e[49m"
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
echo -e "\n\e[41m\e[30mFailed to install ${app} with $scriptname script!\e[39m\e[49m"
|
|
|
|
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 [ "$(cat "${DIRECTORY}/data/status/${app}" 2>/dev/null)" == '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
|
|
|
|
|
|
|
|
echo -e "\e[96mUninstalling $app\e[39m"
|
|
|
|
cd $HOME
|
|
|
|
echo 'corrupted' > "${DIRECTORY}/data/status/${app}"
|
|
|
|
if "${DIRECTORY}/apps/${app}/uninstall" ; then
|
|
|
|
echo 'uninstalled' > "${DIRECTORY}/data/status/${app}"
|
|
|
|
echo -e "\n\e[42m\e[30mUninstalled ${app} successfully.\e[39m\e[49m"
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
echo -e "\n\e[41m\e[30mFailed to uninstall ${app}!\e[39m\e[49m"
|
|
|
|
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
|
|
|
|
|
|
|
|
if [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install-32" ];then
|
|
|
|
scriptname='install-32'
|
|
|
|
elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install-64" ];then
|
|
|
|
scriptname='install-64'
|
|
|
|
elif [ -f "${DIRECTORY}/update/pi-apps/apps/${app}/install" ];then
|
|
|
|
scriptname='install'
|
|
|
|
else
|
|
|
|
error "No install script found for the $app app! Please report this to Botspot."
|
|
|
|
fi
|
|
|
|
newinstallhash=$(sha1sum "${DIRECTORY}/update/pi-apps/apps/${app}/${scriptname}" | awk '{print $1}')
|
|
|
|
oldinstallhash=$(sha1sum "${DIRECTORY}/apps/${app}/${scriptname}" | 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
|
|
|
|
else
|
|
|
|
echo "$app is not identical to the online version."
|
|
|
|
fi
|
|
|
|
#else
|
|
|
|
installback=no
|
|
|
|
#if install was changed #if installed already
|
|
|
|
if [ "$newinstallhash" != "$oldinstallhash" ] && [ "$(cat "${DIRECTORY}/data/status/${app}" 2>/dev/null)" == '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"
|
|
|
|
fi
|
|
|
|
|
|
|
|
#move old program to trash
|
|
|
|
gio trash "${DIRECTORY}/apps/${app}" 2>/dev/null
|
|
|
|
|
|
|
|
#failsafe
|
|
|
|
[ -d "${DIRECTORY}/apps/${app}" ] && error "${DIRECTORY}/apps/${app} still exists, despite trying to delete it!"
|
|
|
|
|
|
|
|
#copy new version to apps/
|
|
|
|
cp -rf "${DIRECTORY}/update/pi-apps/apps/${app}" "${DIRECTORY}/apps/${app}"
|
|
|
|
|
|
|
|
if [ "$installback" == 'yes' ] && [ "$(cat "${DIRECTORY}/data/settings/Reinstall after update")" != 'No' ];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 flag: if $2 is 'installedonly', then only check for updates for those apps that are installed
|
|
|
|
if [ "$2" == 'installedonly' ];then
|
|
|
|
installedonly=1
|
|
|
|
else
|
|
|
|
installedonly=0
|
|
|
|
fi
|
|
|
|
|
|
|
|
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!"
|
|
|
|
|
|
|
|
#generate entire app list, combine local apps and online apps to one list
|
|
|
|
applist="$(echo -e "$(ls "${DIRECTORY}/update/pi-apps/apps")\n$(ls "${DIRECTORY}/apps")" | sort | uniq)"
|
|
|
|
|
|
|
|
#installedonly flag enabled. Remove apps that are uninstalled
|
|
|
|
if [ $installedonly == 1 ];then
|
|
|
|
echo "installedonly flag set to 1" 1>&2
|
|
|
|
PREIFS="$IFS"
|
|
|
|
IFS=$'\n'
|
|
|
|
for app in $applist
|
|
|
|
do
|
|
|
|
if [ ! -f "${DIRECTORY}/data/status/${app}" ] || [ "$(cat "${DIRECTORY}/data/status/${app}" 2>/dev/null)" == 'uninstalled' ];then
|
|
|
|
#if app is uninstalled, then remove it from the list.
|
|
|
|
applist="$(echo "$applist" | grep -vx "$app")"
|
|
|
|
echo "Removing ${app} from list because it is uninstalled." 1>&2
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
IFS="$PREIFS"
|
|
|
|
fi
|
|
|
|
|
|
|
|
applist="$(echo "$applist" | tr '\n' '|')"
|
|
|
|
|
|
|
|
#echo "App list: $applist" 1>&2
|
|
|
|
|
|
|
|
updatable=''
|
|
|
|
PREIFS="$IFS"
|
|
|
|
IFS="|"
|
|
|
|
for app in $applist
|
|
|
|
do
|
|
|
|
#echo "app: $app"
|
|
|
|
newhash="$(dirhash "${DIRECTORY}/update/pi-apps/apps/${app}")"
|
|
|
|
oldhash="$(dirhash "${DIRECTORY}/apps/${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
|
|
|
|
IFS="$PREIFS"
|
|
|
|
|
|
|
|
#remove initial '|' character
|
|
|
|
updatable="${updatable:1}"
|
|
|
|
|
|
|
|
if [ -z "$updatable" ];then
|
|
|
|
updatable='.'
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo -e "\e[97mThese apps can be updated:\n${updatable}"
|
|
|
|
elif [ "$1" == 'update-all' ];then
|
|
|
|
#UPDATE-ALL
|
|
|
|
#for this operation, a program name cannot be specified.
|
|
|
|
PREIFS="$IFS"
|
|
|
|
IFS='|'
|
|
|
|
updatable="$("${DIRECTORY}/manage" check-all | tail -1)"
|
|
|
|
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
|
|
|
|
IFS="$PREIFS"
|
|
|
|
echo -e '\e[92mOperation completed successfully!\e[39m'
|
|
|
|
else
|
|
|
|
error "Did not understand $1. Allowed values: 'install', 'install-if-not-installed', 'multi-install', 'multi-uninstall', 'update', 'check-all', or 'update-all'."
|
|
|
|
fi
|