123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- #!/usr/bin/env bash
- ##############################################################################################
- # THIS MODULE INCLUDES ALL THE ACTIONS INTENDED TO MANAGE THE APPS INSTALLED FROM THE DATABASE
- # AND ONE OPTION IS FOR LOCAL APPIMAGES INSTEAD
- # OPTIONS: BACKUP/RESTORE, DOWNGRADE, LAUNCHER, LOCK/UNLOCK, NOLIBFUSE, REMOVE
- ##############################################################################################
- # BACKUP
- function _backup_name() {
- printf "\n ◆ To set date and time as a name, press ENTER (default)\n ◆ To set the version as a name, press \"1\"\n ◆ To set a custom name, write anything else\n\n"
- read -r -p " Write your choice here, or leave blank to use \"date/time\": " response
- case "$response" in
- '')
- backupname=$(date +%F-%X | sed 's/://g' | sed 's/-//g')
- ;;
- '1')
- _check_version
- backupname=$(grep -w " ◆ $app_name |" "$AMCACHEDIR"/version-args 2>/dev/null | sed 's:.*| ::')
- ;;
- *)
- backupname="$(echo "$response" | sed 's/ /_/g')"
- ;;
- esac
- }
- function _backup() {
- if [ ! -f "$argpath"/remove ]; then
- echo " \"$2\" is not a valid argument or is not installed."
- else
- read -r -p " Do you wish to backup the current version of $2? (y/N) " yn
- if ! echo "$yn" | grep -i '^y' >/dev/null 2>&1; then
- printf "\n OPERATION ABORTED!\n\n"
- else
- mkdir -p "$HOME/.am-snapshots/$2"
- app_name="$2"
- _backup_name
- if test -d "$HOME/.am-snapshots/$2/$backupname"; then
- echo " 💀 ERROR: \"$2/$backupname\" already exists, ABORTED!"
- echo "$DIVIDING_LINE"
- return 1
- else
- cp -r "$argpath" "$HOME/.am-snapshots/$2/$backupname"
- fi
- echo " SAVED in $HOME/.am-snapshots/$2/$backupname"
- fi
- fi
- echo "$DIVIDING_LINE"
- }
- # RESTORE
- function _overwrite() {
- if [ ! -d "$HOME/.am-snapshots/$2" ]; then
- echo " ERROR: No snapshot for \"$2\" found."
- elif [ ! -f "$argpath"/remove ]; then
- echo " \"$2\" is not a valid argument or is not installed."
- else
- read -r -p " Do you wish to overwrite $2 with an older version? (y,N) " yn
- if ! echo "$yn" | grep -i '^y' >/dev/null 2>&1; then
- printf "\n OPERATION ABORTED! \n\n"
- else
- printf "\n Please, select a snapshot or press CTRL+C to abort:\n\n"
- sleep 1
- select d in "$HOME/.am-snapshots/$2"/*; do
- test -n "$d" && break
- echo ">>> Invalid Selection"
- done
- cp -r --backup=t "$d"/* "$argpath"/
- rm -R -f ./tmp "$argpath"/*~
- echo " RESTORE COMPLETED SUCCESSFULLY!"
- fi
- fi
- echo "$DIVIDING_LINE"
- }
- # DOWNGRADE
- function _downgrade_entries_filter() {
- grep -vi "^#\|version0=" ./AM-updater | grep "api.github.com" \
- | tr '=' '\n' | sed 's/^\$(//g' \
- | tail -1 | sed '1,${
- s/version=$(//g
- s/head -1)/head -100/g
- s#$REPO#'"$REPO"'#g
- s#releases/latest#releases#g
- s#releases #releases?per_page=100 #g
- s#/$tag/$app##g
- }'
- }
- function _downgrade() {
- # Safety checks
- if [ ! -f "$argpath"/AM-updater ]; then
- echo " No AM-updater available for \"$2\", cannot detect any URL!"
- return 1
- elif [ -f "$argpath"/"$2"-rollback ]; then
- cd "$argpath" || return 1
- ./"$2"-rollback || return 1
- return 0
- elif ! grep -q "api.github.com" "$argpath"/AM-updater; then
- echo " The option \"$1\" only works for https://github.com"
- return 1
- fi
- cd "$argpath" || return 1
- entries_list=$(_downgrade_entries_filter)
- urls="$(eval "$entries_list" 2>/dev/null | grep -vi "zsync$")"
- if ! echo "$urls" | grep -q "[0-9]"; then
- echo " ERROR: No valid links found, sorry!"
- exit 1
- fi
- echo "-----------------------------------------------------------------------"
- echo "You have chosen to roll back \"$2\"."
- echo "-----------------------------------------------------------------------"
- echo "Select a URL from this menu (read carefully) or press CTRL+C to abort:"
- echo "-----------------------------------------------------------------------"
- sleep 1
- select d in $urls; do
- test -n "$d" && break
- echo ">>> Invalid Selection"
- done
- cp ./AM-updater ./AM-rollback
- sed -i -e 's/version0/#version0/g' \
- -e 's/appimageupdatetool -Or/#appimageupdatetool -Or/g' ./AM-rollback
- [ -f ./"$2".zsync ] && mv ./"$2".zsync ./"$2".zsync.old
- if wget --version | head -1 | grep -q ' 1.'; then
- sed -i '/wget/c\wget -q --show-progress '"$d"'' ./AM-rollback
- else
- sed -i '/wget/c\wget '"$d"'' ./AM-rollback
- fi
- ./AM-rollback && rm -f ./AM-rollback || return 1
- mv ./"$2".zsync.old ./"$2".zsync 2>/dev/null
- echo "$d" > ./version
- echo "ROLLBACK SUCCESSFUL!"
- }
- # ICON THEME CHANGER
- function _icon_theme() {
- if [ "$AMCLI" = am ] && test -f /usr/local/share/applications/"$arg"*AM.desktop; then
- $SUDOCMD sed -i "s#Icon=$argpath/icons/#Icon=#g" /usr/local/share/applications/"$arg"*AM.desktop 2>/dev/null
- else
- sed -i "s#Icon=$argpath/icons/#Icon=#g" "$DATADIR"/applications/"$arg"*AM.desktop 2>/dev/null
- fi
- _icon_theme_export_to_datadir 2>/dev/null
- }
- # LAUNCHER
- function _launcher_appimage_integration() {
- "$arg" --appimage-extract *.desktop 1>/dev/null && mv ./squashfs-root/*.desktop ./"$appimage".desktop
- "$arg" --appimage-extract .DirIcon 1>/dev/null && mv ./squashfs-root/.DirIcon ./DirIcon
- COUNT=0
- while [ "$COUNT" -lt 10 ]; do # Tries to get the actual icon/desktop if it is a symlink to another symlink
- if [ -L ./"$appimage".desktop ]; then
- LINKPATH="$(readlink ./"$appimage".desktop | sed 's|^\./||' 2>/dev/null)"
- "$arg" --appimage-extract "$LINKPATH" 1>/dev/null && mv ./squashfs-root/"$LINKPATH" ./"$appimage".desktop
- fi
- if [ -L ./DirIcon ]; then
- LINKPATH="$(readlink ./DirIcon | sed 's|^\./||' 2>/dev/null)"
- "$arg" --appimage-extract "$LINKPATH" 1>/dev/null && mv ./squashfs-root/"$LINKPATH" "$DATADIR"/icons/ 1>/dev/null
- fi
- [ ! -L ./"$appimage".desktop ] && [ ! -L ./DirIcon ] && break
- COUNT=$((COUNT + 1))
- done
- sed -i "s#Exec=[^ ]*#Exec=\"$arg\"#g" ./"$appimage".desktop
- mv ./"$appimage".desktop "$DATADIR"/applications/AppImages/"$appimage"-AM.desktop
- rm -R -f ./squashfs-root ./DirIcon
- }
- function _launcher_appimage_bin() {
- mkdir -p "$BINDIR"
- if ! echo "$PATH" | grep "$BINDIR" >/dev/null 2>&1; then
- echo "$DIVIDING_LINE"
- echo "WARNING: \"$BINDIR\" is not in PATH, apps may not run from command line." | fold -sw 77 | sed 's/^/ /g'
- echo "$DIVIDING_LINE"
- fi
- read -r -p " Write a custom command to launch the app, or leave blank: " response
- if [ -z "$response" ]; then
- appimage_cmd=$(echo "$appimage" | tr '[:upper:]' '[:lower:]')
- if ! echo "$appimage" | grep -q -i ".appimage"; then
- [ -n "$BINDIR" ] && printf '#!/bin/sh\n%s' "$arg" >> "$BINDIR"/"$appimage_cmd".appimage \
- && chmod a+x "$BINDIR"/"$appimage_cmd".appimage && echo " New command: \"$appimage_cmd.appimage\" in $BINDIR"
- else
- [ -n "$BINDIR" ] && printf '#!/bin/sh\n%s' "$arg" >> "$BINDIR"/"$appimage_cmd" \
- && chmod a+x "$BINDIR"/"$appimage_cmd" && echo " New command: \"$appimage_cmd\" in $BINDIR"
- fi
- elif command -v "$response" 1>/dev/null; then
- echo " ERROR: the \"$response\" command alredy exists, retry!"
- else
- [ -n "$BINDIR" ] && ln -s "$arg" "$BINDIR"/"$response"
- fi
- }
- function _launcher(){
- if ! test -f "$arg"; then
- echo " ERROR: \"$arg\" not found"
- elif ! strings -d "$arg" 2>/dev/null | grep -F -q 'if you run it with the --appimage-extract option'; then
- echo " ERROR: \"$arg\" is NOT an AppImage"
- else
- printf " ◆ File: %s\n" "$arg"
- appimage=$(basename -- "$arg")
- mkdir -p "$DATADIR"/applications/AppImages
- mkdir -p "$DATADIR"/icons
- chmod a+x "$arg"
- cd "$(dirname "$arg")" || return
- _launcher_appimage_integration 2>/dev/null
- _launcher_appimage_bin
- fi
- }
- # LOCK/UNLOCK
- function _lock() {
- if [ ! -f "$argpath"/AM-updater ]; then
- echo " \"$AMCLIUPPER\" cannot manage updates for $2, \"AM-updater\" file not found!"
- return 1
- fi
- read -r -p " Do you wish to keep $2 at its current version? (y/N) " yn
- if echo "$yn" | grep -i '^y' >/dev/null 2>&1; then
- mv "$argpath"/AM-updater "$argpath"/AM-LOCK 1>/dev/null
- echo " $2 has been locked at current version!"
- else
- echo " Operation aborted!"
- return 1
- fi
- }
- function _unlock() {
- if ! test -f "$argpath"/AM-LOCK; then
- echo " \"$2\" cannot be unlocked, \"AM-LOCK\" file not found!"
- return 1
- fi
- read -r -p " Do you wish to unlock updates for $2? (Y/n) " yn
- if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then
- echo " $2 is still locked at current version!"
- return 1
- else
- mv "$argpath"/AM-LOCK "$argpath"/AM-updater 1>/dev/null
- echo " \"$2\" can now receive updates!"
- fi
- }
- # NO LIBFUSE
- function _nolibfuse() {
- AMCLIPATH_ORIGIN="$AMCLIPATH"
- target="$(echo "${2}" | tr '[:lower:]' '[:upper:]')"
- # safety checks
- if ! cd "$argpath" 2>/dev/null; then
- echo " ⚠️ Error: \"$target\" is NOT installed."
- return 1
- fi
- string="$(strings -d "./$2" 2>/dev/null)"
- if ! echo "$string" | grep -q -- 'run it with the --appimage-extract'; then
- echo " ⚠️ Error: $target is NOT an AppImage."
- return 1
- elif ! echo "$string" | grep -q -- 'AppImages require FUSE to run'; then
- echo " ◆ $target is already a new generation AppImage."
- return 1
- elif test -f ./*.zsync; then
- echo "-----------------------------------------------------------------------"
- echo " Warning! Your AppImage uses \"zsync\" to update."
- echo " The .zsync file will be removed and will no longer work"
- echo " your \"AM-updater\" will likely still be able to update the AppImage"
- echo " by comparing the old vs new version url, but it is not guaranteed"
- read -r -p " Do you want to proceede anyway? (N/y) " yn
- if ! echo "$yn" | grep -i '^y' >/dev/null 2>&1; then
- return 1
- fi
- fi
- appimagetool="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$ARCH.AppImage"
- printf " ...downloading appimagetool\r"
- wget -q "$appimagetool" -O ./appimagetool || return 1
- printf '#!/bin/sh\nexit 0' > ./desktop-file-validate # hack due to https://github.com/AppImage/appimagetool/pull/47
- chmod a+x ./appimagetool ./desktop-file-validate
- printf " ...extracting the AppImage\r"
- ./"$2" --appimage-extract >/dev/null 2>&1 && chmod 0755 ./squashfs-root
- printf " ...trying to convert in new generation AppImage\r"
- PATH="$PATH:$PWD" ARCH="$(uname -m)" ./appimagetool -n ./squashfs-root >/dev/null 2>&1
- if ! test -f ./*.AppImage; then
- echo " 💀Error when trying to convert $target. Operation Aborted."
- rm -R -f ./appimagetool ./squashfs-root ./desktop-file-validate
- return 1
- fi
- mv ./"$2" ./"$2".old && mv ./*.AppImage ./"$2" || return 1
- echo " ◆ $target has been converted to a new generation AppImage."
- rm -rf ./appimagetool ./squashfs-root ./desktop-file-validate ./*.zsync
- if [ -f ./AM-updater ] && ! grep -q 'nolibfuse' ./AM-updater; then
- sed -i "s/^else/ echo y | $AMCLIPATH_ORIGIN nolibfuse \"\$APP\"\n notify-send \"\$APP has been converted too\!\"\nelse/g" ./AM-updater 2>/dev/null
- echo " The next update may replace this AppImage with a Type2 one"
- echo " so I added this command to the bottom of the \"AM-updater\" script!"
- fi
- echo " Contact the upstream developers to make them officially upgrade!"
- read -r -p " Do you wish to remove the old libfuse2 AppImage? (Y/n) " yn
- if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then
- return 1
- else
- rm -f ./*.old
- fi
- }
- # REMOVE
- function _detect_path_to_remove() {
- if [ -d "$APPMAN_APPSPATH"/"$arg" ]; then
- RMPATH="1"
- elif [ -d "$APPSPATH"/"$arg" ]; then
- [ -w "$APPSPATH"/"$arg" ] && $SUDOCMD echo -e "\r" >/dev/null
- RMPATH="1"
- else
- RMPATH=""
- fi
- echo "$DIVIDING_LINE"
- }
- function _remove() {
- [ "$AMCLI" = am ] && _detect_appman_apps
- _detect_path_to_remove
- [ -z "$RMPATH" ] && echo -e " \"${RED}$arg\033[0m\" is not a valid \"APPNAME\", see \"$AMCLI -f\" for more." && return 1
- read -r -p " ◆ Do you wish to remove \"$arg\"? (Y/n) " yn
- if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then
- echo -e " \"${LightBlue}$arg\033[0m\" has not been removed!"
- else
- [ "$AMCLI" = am ] && "$APPMAN_APPSPATH"/"$arg"/remove 2>/dev/null || $SUDOCMD "$APPSPATH"/"$arg"/remove 2>/dev/null || return 1
- _clean_amcachedir
- sleep 0.1
- echo -e " \"${Green}$arg\033[0m\" has been removed!"
- fi
- [ -d "$DATADIR"/icons/hicolor/scalable/apps ] && find "$DATADIR"/icons/hicolor/scalable/apps -xtype l -exec rm {} \;
- }
- function _hard_remove() {
- [ "$AMCLI" = am ] && _detect_appman_apps
- _detect_path_to_remove
- [ -z "$RMPATH" ] && echo -e " \"${RED}$arg\033[0m\" is not a valid \"APPNAME\", see \"$AMCLI -f\" for more." && return 1
- [ "$AMCLI" = am ] && "$APPMAN_APPSPATH"/"$arg"/remove 2>/dev/null || $SUDOCMD "$APPSPATH"/"$arg"/remove 2>/dev/null || return 1
- _clean_amcachedir
- sleep 0.1
- echo -e " \"${Green}$arg\033[0m\" has been removed!"
- [ -d "$DATADIR"/icons/hicolor/scalable/apps ] && find "$DATADIR"/icons/hicolor/scalable/apps -xtype l -exec rm {} \;
- }
- ###########################################################################
- # OPTIONS AVAILABLE IN THIS MODULE
- ###########################################################################
- # Main logic
- [ -z "$2" ] && echo " USAGE: $AMCLI $1 [ARGUMENT]" && exit 1
- case "$1" in
- 'backup'|'-b')
- # Do a snapshot of an installed app
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _backup "${@}"
- shift
- done
- ;;
- 'downgrade'|'--rollback')
- # Downgrade the installed app to a previous version, from its online source
- _online_check
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _downgrade "${@}"
- _clean_amcachedir
- _update_list_updatable_apps
- shift
- done
- ;;
- 'icons'|'--icons')
- # Place local AppImages into the menu by dragging and dropping them into the terminal
- _determine_args
- if [ "$2" = "--all" ]; then
- entries="$ARGS"
- read -r -p " ◆ Do you wish to allow custom icon theming for ALL the apps? (y,N) " yn
- else
- entries="$(echo "$@" | cut -f2- -d ' ')"
- read -r -p " ◆ Do you wish to allow custom icon theming for the selected apps? (y,N) " yn
- fi
- if echo "$yn" | grep -i '^y' >/dev/null 2>&1; then
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _icon_theme "${@}"
- done
- echo " ✔ Success!"
- else
- echo " ✖ Aborted!"
- fi
- ;;
- 'launcher'|'--launcher')
- # Place local AppImages into the menu by dragging and dropping them into the terminal
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- echo "---------------------------------------------------------------------"
- _launcher "${@}"
- done
- echo "---------------------------------------------------------------------"
- ;;
- 'lock')
- # Lock the version of an installed app
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _lock "${@}"
- shift
- done
- ;;
- 'unlock')
- # Unlock the version of an installed app
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _unlock "${@}"
- shift
- done
- ;;
- 'nolibfuse')
- # Convert old AppImages to a new standard and get rid of libfuse2 dependency
- _online_check
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _nolibfuse "${@}"
- _remove_info_files
- shift
- done
- ;;
- 'overwrite'|'-o')
- # Restore an app to a previous version using a snapshot (see "backup" or "-b", above)
- _determine_args
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- argpath=$(echo "$ARGPATHS" | grep "/$arg$")
- _overwrite "${@}"
- _remove_info_files
- shift
- done
- ;;
- 'remove'|'-r')
- # Remove apps
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- _remove "${@}"
- _remove_info_files
- shift
- done
- echo "------------------------------------------------------------------------------"
- ;;
- '-R')
- # Remove apps without confirmation
- entries="$(echo "$@" | cut -f2- -d ' ')"
- for arg in $entries; do
- _hard_remove "${@}"
- _remove_info_files
- shift
- done
- echo "------------------------------------------------------------------------------"
- ;;
- esac
|