diff --git a/README.md b/README.md index bdc8013..b96d214 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,19 @@ appz [mngr] [i|r|l|C|u|U|s|S|I|c|h] [pkg]... -> h | help show this message ``` -#### Supported managers : +## Supported managers : - pacman - yay - pipx -#### Installation +## Installation ```bash git clone https://github.com/MyOS-ArchLinux/appz cd appz ... ``` + +## License +[GPLv3](https://github.com/MyOS-ArchLinux/appz/blob/main/LICENSE) + +inspired by [cpm](https://github.com/willeccles/cpm) - MIT License diff --git a/appz b/appz index 8919387..74ec8a2 100644 --- a/appz +++ b/appz @@ -11,10 +11,26 @@ APPZ_FORCE_ACT=false APPZ_LOG=false APPZ_VERBOSE=false APPZ_MNGR=pacman -APPZ_ACTN=help # functions ## tools +### prnt options +prnt_opt() { + >&2 printf "\033[33;1m-> \033[35;1m%s | %s\033[m %s\n" "$1" "$2" "$3" +} + +prnt_log() { + [[ "${APPZ_LOG:-false}" == false ]] && return + echo "$@" +} + +prnt_err() { + printf "\033[38;5;1merr:\033[m %s\n" "$@" +} + +prnt(){ + echo ":: $@" +} ### check for deps and functions has(){ case "$(command -v "$1" 2>/dev/null)" in @@ -27,7 +43,7 @@ tot(){ while read -r ; do i=$((i + 1)) done - echo "${APPZ_MNGR:?} : $i packages" + echo "${APPZ_MNGR:?} : $i ${1:-packages}" } ### check for multiple deps @@ -39,18 +55,10 @@ need(){ done [ -n "${dependencies_not_installed}" ] && \ { - echo "err : missing dependencies, please install: ${dependencies_not_installed%??}." + prnt_err "missing dependencies, please install: ${dependencies_not_installed%??}." return 1 ; } -} -### prnt options -prnt_opt() { - >&2 printf "\033[33;1m-> \033[35;1m%s | %s\033[m %s\n" "$1" "$2" "$3" -} - -prnt_log() { - [[ "${APPZ_LOG:-false}" == false ]] && return - echo "$@" + return 0 } ### _prompt @@ -67,9 +75,13 @@ is_file_uptodate(){ } ## internal +prnt_mngr_version(){ + echo "mngr : \`${APPZ_MNGR_NAME:-$APPZ_MNGR}\` v${APPZ_MNGR_VERSION:-??}" +} + appz_help(){ >&2 echo "${APPZ_SCRIPT_NAME} [mngr] [i|r|l|C|u|U|s|S|I|c|h] [pkg]..." - echo "mngr : \`${APPZ_MNGR_NAME:-$APPZ_MNGR}\` v${APPZ_MNGR_VERSION}" + prnt_mngr_version if has appz_usage ;then appz_usage else @@ -120,7 +132,7 @@ else fi case "$1" in - --version) + -V|--version) echo "${APPZ_SCRIPT_NAME} ${APPZ_VERSION} Copyright © 2023-2024 MyOS Project " exit ;; @@ -137,67 +149,71 @@ if [ -f "${APPZ_CONFIG_DIR}/addons/${APPZ_MNGR}" ] ; then . "${APPZ_CONFIG_DIR}/addons/${APPZ_MNGR}" has appz_usage || prnt_log "log : appz_usage() is not implemented in \`${APPZ_MNGR}\` menu, fallback to to local" else - echo "err : mngr \`${APPZ_MNGR}\` not found" + prnt_err "mngr \`${APPZ_MNGR}\` not found" exit 1 fi while [ "$1" ]; do + if [ -z ${APPZ_ACTN} ] ; then + case "$1" in + i|install) + APPZ_ACTN='install' + shift + ;; + r|remove) + APPZ_ACTN='remove' + shift + ;; + l|list) + APPZ_ACTN='list' + shift + ;; + u|update) + APPZ_ACTN='update' + shift + ;; + U|upgrade) + APPZ_ACTN='upgrade' + shift + ;; + s|search) + APPZ_ACTN='search' + shift + ;; + S|show|I|info) + APPZ_ACTN='show' + shift + ;; + c|clean) + APPZ_ACTN='clean' + shift + ;; + h|help|"") + APPZ_ACTN='help' + shift + ;; + has) + APPZ_ACTN='has' + shift + ;; + C|count) + APPZ_ACTN='count' + shift + ;; + esac + fi case "$1" in - i|install) - APPZ_ACTN='install' - shift - ;; - r|remove) - APPZ_ACTN='remove' - shift - ;; - l|list) - APPZ_ACTN='list' - shift - ;; - u|update) - APPZ_ACTN='update' - shift - ;; - U|upgrade) - APPZ_ACTN='upgrade' - shift - ;; - s|search) - APPZ_ACTN='search' - shift - ;; - S|show|I|info) - APPZ_ACTN='show' - shift - ;; - c|clean) - APPZ_ACTN='clean' - shift - ;; - h|help|"") - APPZ_ACTN='help' - shift - ;; - has) - APPZ_ACTN='has' - shift - ;; - C|count) - APPZ_ACTN='count' - shift + -v) + prnt_mngr_version + exit 0 ;; -f|--force) APPZ_FORCE_ACT=true prnt_log "log : APPZ_FORCE_ACT is set to true" shift ;; - "-v") - echo "mngr : \`${APPZ_MNGR_NAME:-$APPZ_MNGR}\` v${APPZ_MNGR_VERSION:-??}" - exit 0 - ;; -*) - echo "err : option $1 is not supported" + prnt_err "option $1 is not supported" exit 1 ;; *) @@ -207,16 +223,16 @@ while [ "$1" ]; do done # check if action is aviable -case "${APPZ_ACTN:?}" in +case "${APPZ_ACTN:-help}" in "clean"|"has"|"help"|"install"|"list"|"remove"|"search"|"show"|"update"|"upgrade"|"count") - has "appz_${APPZ_ACTN}" || { echo "err : appz_${APPZ_ACTN}() is not implemented in \`${APPZ_MNGR}\` mngr."; exit 1;} + has "appz_${APPZ_ACTN:-help}" || { prnt_err "appz_${APPZ_ACTN:-help}() is not implemented in \`${APPZ_MNGR}\` mngr."; exit 1;} appz_run() { - has "appz_${APPZ_ACTN}" || return 1 - appz_${APPZ_ACTN} "$@" + has "appz_${APPZ_ACTN:-help}" || return 1 + appz_${APPZ_ACTN:-help} "$@" } ;; *) - echo "err : action \`${APPZ_ACTN}\` is not supported!!" + prnt_err "action \`${APPZ_ACTN}\` is not supported!!" exit 1 ;; esac diff --git a/config/addons/crx b/config/addons/crx new file mode 100644 index 0000000..d564bb3 --- /dev/null +++ b/config/addons/crx @@ -0,0 +1,272 @@ +#!/usr/bin/env bash +APPZ_MNGR_VERSION="0.0.2 (wip)" +APPZ_MNGR_NAME="crx" +APPZ_DATA_DIR_CRX="${APPZ_DATA_DIR:?}/crx" +APPZ_CACHE_DIR_CRX="${APPZ_CACHE_DIR:?}/crx" + +need xmllint curl sha256sum dd od zip jsonlint cat awk fzf || exit 1 + +if has chromium ; then + CHROME_VER=$(chromium --version | awk '{print $2}') +elif has brave; then + CHROME_VER=$(brave --version | awk '{print $3}') +else + CHROME_VER='112.0.5615.165' +fi + +CHROME_UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROME_VER:?} Safari/537.36}" +CHROME_STR_URL="https://chrome.google.com/webstore/detail/" +CHROME_REF_URL="https://chrome.google.com/webstore/" +CHROME_REF="${CHROME_UA:+$CHROME_REF_URL}" + +mkdir -p "${APPZ_DATA_DIR_CRX:?}" +mkdir -p "${APPZ_CACHE_DIR_CRX:?}" + +crx_addon_id_valid(){ + case "${1}" in ('' | *[!a-z]* | *" "*) prnt_err "invalid extention ID \"${1}\"" >&2 ; return 1 ; esac +} + +crx_download_addons_metadata(){ + if (( $# == 0 )) ; then + local ARGS=$(< /dev/stdin) + else + local ARGS=$@ + fi + for APP_ID in ${ARGS} ; do + echo "url = https://clients2.google.com/service/update2/crx?response=updatecheck&acceptformat=crx2,crx3&prodversion=${CHROME_VER}&x=id%3D${APP_ID}%26uc" + printf "output = %s\n" "${APPZ_CACHE_DIR_CRX:?}/${APP_ID}.xml" + done | curl -Z --parallel-max 10 -A "${CHROME_UA}" -H "accept-encoding:gzip" --compressed --referer "${CHROME_REF}" -K - &>/dev/null +} + +crx_check_if_metadata_valid(){ + local err_msg=$(xmllint --xpath "string(//@status)" "${APPZ_CACHE_DIR_CRX:?}/${@}.xml") + case "${err_msg}" in + "ok") + return 0 ;; + *) + prnt_err "\`${err_msg}\`" ; return 1 ;; + esac +} + +crx_get_download_url_from_metadata(){ + xmllint --xpath "string(//@codebase)" "${APPZ_CACHE_DIR_CRX:?}/${@}.xml" 2>/dev/null +} + +crx_get_download_hash_from_metadata(){ + xmllint --xpath "string(//@hash_sha256)" "${APPZ_CACHE_DIR_CRX:?}/${@}.xml" 2>/dev/null +} + +crx_download_addon_package(){ + local ADDON_DOWNLOAD_URL=$(crx_get_download_url_from_metadata "${@:?}") + local ADDON_DOWNLOAD_FILE="${APPZ_CACHE_DIR_CRX:?}/${@}.crx" + curl -fL --progress-bar -A "${CHROME_UA}" --referer "${CHROME_REF}" -o "${ADDON_DOWNLOAD_FILE:?}" -- "${ADDON_DOWNLOAD_URL}" && exitCode=0 || exitCode=$? + if [ ! "${exitCode:?}" -eq 0 ]; then + rm -fr "${ADDON_DOWNLOAD_FILE:?}" + return 1 + fi +} + +crx_check_addon_package_hash(){ + local ADDON_HASH_STRING=$(crx_get_download_hash_from_metadata "${@:?}") + echo "${ADDON_HASH_STRING:?} ${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | sha256sum --check --status || return 1 +} + +crx_check_addon_package_valid(){ + CRMAGIC=$(dd if="${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" bs=4 count=1 2>/dev/null) + [ "$CRMAGIC" = Cr24 ] || { prnt_err "$@ is not a valid crx file." ; return 1;} + MANIFEST_VERSION=$(od -An -j4 -N4 -tu "${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | tr -d ' \t') + case $MANIFEST_VERSION in + 2) + KEY_LEN=$(od -An -j8 -N4 -tu "${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | tr -d ' \t') + SIG_LEN=$(od -An -j12 -N4 -tu "${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | tr -d ' \t') + OFFSET=$((16 + KEY_LEN + SIG_LEN)) + ;; + 3) + HEADER_LEN=$(od -An -j8 -N4 -tu "${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | tr -d ' \t') + OFFSET=$((12 + HEADER_LEN)) + ;; + *) + return 1 # "don't know how to deal with extensions version $MANIFEST_VERSION" + ;; + esac + ZIPMAGIC=$(od -An -j$OFFSET -N4 -tx "${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" | tr -d ' \t') + [ $ZIPMAGIC = 04034b50 ] || { prnt_err "$@ is not a valid zip file." ; return 1;} + dd if="${APPZ_CACHE_DIR_CRX:?}/${@:?}.crx" of="${APPZ_CACHE_DIR_CRX:?}/${@:?}.zip" ibs=1 skip=$OFFSET 2>/dev/null +} + +crx_unpack_addon_package(){ + local ADDON_DIR="${APPZ_DATA_DIR_CRX}/venvs/${@:?}" + rm -fr "${ADDON_DIR:?}" + mkdir -p "${ADDON_DIR:?}" + unzip -qqo "${APPZ_CACHE_DIR_CRX:?}/${@:?}.zip" -d "${ADDON_DIR:?}" > /dev/null 2>&1 +} + +get_local_ext_name(){ + local ADDON_DIR_TMP="${APPZ_DATA_DIR_CRX}/venvs/${@:?}" + local ADDON_DATA_TMP=$(cat "${ADDON_DIR_TMP:?}/manifest.json") + local ADDON_NAME_TMP=$(echo "${ADDON_DATA_TMP:?}" | jq -r ".name") + case "${ADDON_NAME_TMP}" in + "__MSG_"*) + ADDON_NAME_TMP="${ADDON_NAME_TMP##__MSG_}" + ADDON_NAME_TMP="${ADDON_NAME_TMP%%__}" + local ADDON_LOCALE=$(echo "${ADDON_DATA_TMP:?}" | jq -r ".default_locale") + cat "${APPZ_DATA_DIR_CRX}/venvs/${@:?}/_locales/${ADDON_LOCALE}/messages.json" | jq -r ".${ADDON_NAME_TMP}.message" 2>/dev/null || \ + cat "${APPZ_DATA_DIR_CRX}/venvs/${@:?}/_locales/${ADDON_LOCALE}/messages.json" | jsonlint -Sf | jq -r ".${ADDON_NAME_TMP}.message" + ;; + *) + echo "${ADDON_NAME_TMP}" + ;; + esac +} + +crx_install_addon_package(){ + mkdir -p "${APPZ_DATA_DIR_CRX:?}/addons" + local ADDON_DIR="${APPZ_DATA_DIR_CRX}/venvs/${@:?}" + local ADDON_DATA=$(cat "${ADDON_DIR:?}/manifest.json") + local ADDON_NAME=$(get_local_ext_name "${@}" | sed 's/\//∕/') + local ADDON_ICON=$(echo "${ADDON_DATA:?}" | jq -r ".icons|.[]" | tail -1) + local ADDON_ICON_EX="${ADDON_ICON##*.}" + [ -f "${ADDON_DIR:?}/${ADDON_ICON}" ] && cp -f "${ADDON_DIR:?}/${ADDON_ICON}" "${ADDON_DIR:?}/.folder.${ADDON_ICON_EX}" + rm -fr "${APPZ_DATA_DIR_CRX:?}/addons/${ADDON_NAME:?}" + ln -s "${APPZ_DATA_DIR_CRX}/venvs/${@:?}" "${APPZ_DATA_DIR_CRX:?}/addons/${ADDON_NAME:?}" +} + +appz_install() { + local ADDON_ID="$1" + crx_addon_id_valid "${ADDON_ID:?}" || { prnt_err "crx_addon_id_valid() failed" ; return 1 ; } + if ! is_file_uptodate "${APPZ_CACHE_DIR_CRX:?}/${ADDON_ID:?}.xml" ; then + crx_download_addons_metadata "${ADDON_ID:?}" || { prnt_err "crx_download_addons_metadata() failed" ; return 1 ; } + fi + crx_check_if_metadata_valid "${ADDON_ID:?}" || { prnt_err "crx_check_if_metadata_valid() failed" ; return 1 ; } + local installed_version=$(crx_get_installed_version "${ADDON_ID:?}" || echo 0) + local available_version=$(crx_get_available_version "${ADDON_ID:?}") + + [ -z "${available_version}" ] && { prnt_err "can get available_version for ${ADDON_ID}" ; return 1; } + + if [ "${installed_version:?}" = "${available_version:?}" ]; then # if installed Version != available Version + local TMP_NAME=$(get_local_ext_name ${ADDON_ID}) + echo ":: addon \`${TMP_NAME:?}\` is up to date" ; return 0 + fi + if ! is_file_uptodate "${APPZ_CACHE_DIR_CRX:?}/${ADDON_ID:?}.crx" ; then + crx_download_addon_package "${ADDON_ID:?}" || { prnt_err "crx_download_addon_package() failed" ; return 1 ; } + fi + crx_check_addon_package_hash "${ADDON_ID:?}" || { prnt_err "crx_check_addon_package_hash() failed" ; return 1 ; } + if ! is_file_uptodate "${APPZ_CACHE_DIR_CRX:?}/${ADDON_ID:?}.zip" ; then + crx_check_addon_package_valid "${ADDON_ID:?}" || { prnt_err "crx_check_addon_package_valid() failed" ; return 1 ; } + fi + crx_unpack_addon_package "${ADDON_ID:?}" || { prnt_err "crx_unpack_addon_package() failed" ; return 1 ; } + crx_install_addon_package ${ADDON_ID:?} || { prnt_err "crx_install_addon_package() failed" ; return 1 ; } +} + +crx_update_db(){ + for TMP_ID in "${APPZ_DATA_DIR_CRX}/venvs/"*/ ; do + TMP_ID=${TMP_ID%"${TMP_ID##*[!/]}"} + TMP_ID=${TMP_ID##*/} + if ! is_file_uptodate "${APPZ_CACHE_DIR_CRX:?}/${TMP_ID:?}.xml" ; then + printf '%s ' ${TMP_ID} + fi + done | crx_download_addons_metadata +} + +appz_update(){ + crx_update_db + for TMP_ID in "${APPZ_DATA_DIR_CRX}/venvs/"*/ ; do + TMP_ID=${TMP_ID%"${TMP_ID##*[!/]}"} + TMP_ID=${TMP_ID##*/} + local TMP_NAME=$(get_local_ext_name ${TMP_ID}) + local installed_version=$(crx_get_installed_version "$TMP_ID") + local available_version=$(crx_get_available_version "$TMP_ID") + [ -z "${available_version}" ] && { prnt_err "can get available_version for ${TMP_NAME} - (${TMP_ID})" ; continue; } + if [ ! "${installed_version:?}" = "${available_version:?}" ]; then # if installed Version != available Version + printf -- '- %s : %s >> %s \n' "${TMP_NAME:?}" "${installed_version:?}" "${available_version:?}" + fi + done +} + +crx_get_available_version(){ + xmllint --xpath "string(//@version)" "${APPZ_CACHE_DIR_CRX:?}/${@}.xml" 2>/dev/null +} + +crx_get_installed_version(){ + jq -r ".version" "${APPZ_DATA_DIR_CRX}/venvs/${@:?}/manifest.json" 2>/dev/null +} + +appz_upgrade(){ + for TMP_ID in "${APPZ_DATA_DIR_CRX}/venvs/"*/ ; do + TMP_ID=${TMP_ID%"${TMP_ID##*[!/]}"} + TMP_ID=${TMP_ID##*/} + local TMP_NAME=$(get_local_ext_name ${TMP_ID}) + local installed_version=$(crx_get_installed_version "$TMP_ID") + local available_version=$(crx_get_available_version "$TMP_ID") + [ -z "${available_version}" ] && { prnt_err "can get available_version for ${TMP_NAME} - (${TMP_ID})" ; continue; } + if [ ! "${installed_version:?}" = "${available_version:?}" ]; then # if installed Version != available Version + printf -- '- %s : %s \n' "${TMP_ID:?} - ${TMP_NAME:?}" "${available_version:?}" + appz_install "${TMP_ID}" + fi + done +} + +appz_clean(){ + printf '%s\n' "crx cache directory: ${CRX_CACH_DIR} " + _prompt "==> Do you want to remove all crx metadata cache?" && rm -frv "${APPZ_CACHE_DIR_CRX:?}"/* +} + +crx_get_search_data(){ + curl -s "https://chrome.google.com/webstore/ajax/item?pv=20210820&hl=en&count=20&category=extensions&searchTerm=${@}&sortBy=0" \ + -X POST -H "accept-encoding:gzip" --compressed --silent \ + --referer "${CHROME_REF}" -A "${CHROME_UA}" \ + | awk '{if (NR == 1) {print substr($0, 6)} else {print}}' +} + +appz_search(){ + [ -z "${1}" ] && { prnt_err "arg is not provided" ; return 1 ;} + local search_data=$(crx_get_search_data "${@}" | jq -r '.[1]|.[1]|.[]| "\(.[0]) \(.[1]) by \(.[2])"') + [ -z "${search_data}" ] && { prnt_err "failed to get search data" ; return 1;} + local selected_addon_id=$(echo "${search_data}" | fzf -i -e -m --cycle --no-sort --layout=reverse --preview-window=right,90 --preview "appz ${APPZ_MNGR:?} show {+1}" --with-nth='2..' --delimiter=" " -q "${*:-}" | awk '{print $1}') + [ -z "$selected_addon_id" ] && return 0 + _prompt "do you wanna install $selected_addon_id ?" && appz_install "$selected_addon_id" +} + +crx_get_addon_info(){ + curl -s "https://chrome.google.com/webstore/ajax/detail?hl=en&pv=20210820&id=${@}" \ + -X POST -H "accept-encoding:gzip" --compressed --silent \ + --referer "${CHROME_REF}" -A "${CHROME_UA}" \ + | awk '{if (NR == 1) {print substr($0, 6)} else {print}}' +} + +appz_show(){ + [ -z "$1" ] && { prnt_err "arg is not provided" ; return 1 ;} + crx_addon_id_valid "$1" || return 1; + local search_data=$(crx_get_addon_info "$1") + local addon_id=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[0]') + local addon_name=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[1]') + local addon_version=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[6]') + local addon_author_name=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[2]') + local addon_author_mail=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[35]|.[0]') + local addon_description=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[6]') + local addon_category=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[10]') + local addon_description_big=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[1]') + local addon_url=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[5]') + local addon_date=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[7]') + local addon_size=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[25]') + local addon_slug=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[61]') + local addon_req=$(echo "${search_data}" | jq -r '.[1]|.[1]|.[0]|.[58]') + echo "Repository : chrome-web-store" + echo "Name : ${addon_name}" + echo "Version : ${addon_version}" + echo "Description : ${addon_description}" + echo "Category : ${addon_category}" + echo "Chrome Version : ${addon_req} +" + echo "URL : ${addon_url}" + echo "Store URL : ${CHROME_STR_URL}${addon_id}" + echo "Provides : ${addon_slug}" + echo "Download Size : ${addon_size}" + echo "Author : ${addon_author_name} <${addon_author_mail}>" + echo "Build Date : ${addon_date}" + echo "Validated By : SHA-256 Sum" +# echo "Validated By : MD5 Sum SHA-256 Sum Signature" +} + +appz_count(){ + ls "${APPZ_DATA_DIR_CRX}/venvs/" | tot +} diff --git a/config/addons/pacman b/config/addons/pacman index a363f49..7c89356 100644 --- a/config/addons/pacman +++ b/config/addons/pacman @@ -12,10 +12,10 @@ appz_list(){ } appz_search(){ - local selected_app=$(pacman -Ssq | fzf -i -e -m --preview 'pacman -Si {}' --layout=reverse -q "${*:-}" ) - [ -z "$selected_app" ] && return 0 - pacman -Si "$selected_app" - _prompt "do you wanna install $selected_app ?" && sudo pacman -S "$selected_app" + local selected_app=$(pacman -Ssq | fzf -i -e -m --preview 'pacman -Si {}' --layout=reverse -q "${*:-}" ) + [ -z "$selected_app" ] && return 0 + pacman -Si "$selected_app" + _prompt "do you wanna install $selected_app ?" && sudo pacman -S "$selected_app" } appz_install() { @@ -37,30 +37,35 @@ appz_install() { } appz_update_pacman_mirrorlist(){ - reflector --verbose --protocol https --latest 10 --sort rate --save "${pacman_mirrorlist:?}" - echo "#\n" >> "${pacman_mirrorlist:?}" - reflector --country Spain,Germany,France,Sweden,Netherlands --protocol https --latest 40 >> "${pacman_mirrorlist:?}" - awk ' !x[$0]++' "${pacman_mirrorlist:?}" > "${pacman_mirrorlist:?}_new" - sudo mv -f -v "${pacman_mirrorlist:?}_new" /etc/pacman.d/mirrorlist + reflector --verbose --protocol https --latest 10 --sort rate --save "${pacman_mirrorlist:?}" || { prnt_err "error to get update mirrors list" ;return 1 ; } + echo "#\n" >> "${pacman_mirrorlist:?}" + reflector --country Spain,Germany,France,Sweden,Netherlands --protocol https --latest 40 >> "${pacman_mirrorlist:?}" || { prnt_err "error to get update mirrors list" ;return 1 ; } + awk ' !x[$0]++' "${pacman_mirrorlist:?}" > "${pacman_mirrorlist:?}_new" + _prompt "do you want to save mirror list" || { echo "skipped update mirrors"; return 0; } + sudo mv -f -v "${pacman_mirrorlist:?}_new" /etc/pacman.d/mirrorlist } appz_update(){ if ! is_file_uptodate "${pacman_mirrorlist:?}"; then _prompt "do you want to update pacman mirror list" && \ appz_update_pacman_mirrorlist || \ - touch "${pacman_mirrorlist:?}" + rm -fr "${pacman_mirrorlist:?}" + fi + echo ":: checking for new updates" + if [ "${APPZ_FORCE_ACT:?}" == true ] ; then + sudo pacman -Syy; + else + sudo pacman -Sy; fi - sudo pacman -Sy; - - if pacman -Qu | grep -v "\[ignored\]" -q; then - notify-send "🎁 apps" "New updates available." - printf -- '\033[1;32m%s \033[0m\n' "-> New updates available." - pacman -Qu; - else - notify-send "📦 apps" "Sync complete. No new packages for update." - printf -- '\033[1;31m%s \033[0m\n' "-> Sync complete. No new packages for update." - fi + if pacman -Qu | grep -v "\[ignored\]" -q; then + notify-send "🎁 apps" "New updates available." + printf -- '\033[1;32m%s \033[0m\n' "-> New updates available." + pacman -Qu; + else + notify-send "📦 apps" "Sync complete. No new packages for update." + printf -- '\033[1;31m%s \033[0m\n' "-> Sync complete. No new packages for update." + fi } appz_upgrade(){ @@ -83,16 +88,16 @@ appz_remove(){ } appz_has(){ - while [ "$1" ]; do - if $(pacman -Qnq $1 >/dev/null 2>&1); then - printf ' %s \033[32;1m\t%s \033[0m\n' "- $1" "installed" - elif $(pacman -Ssq "^$1" >/dev/null 2>&1); then - printf ' %s \033[31;1m\t%s \033[0m\n' "- $1" "not installed" - else - printf ' %s \033[31;1m\t%s \033[0m\n' "- $1" "not available in pacman" - fi - shift - done + while [ "$1" ]; do + if $(pacman -Qnq $1 >/dev/null 2>&1); then + printf ' %s \033[32;1m\t%s \033[0m\n' "- $1" "installed" + elif $(pacman -Ssq "^$1" >/dev/null 2>&1); then + printf ' %s \033[31;1m\t%s \033[0m\n' "- $1" "not installed" + else + printf ' %s \033[31;1m\t%s \033[0m\n' "- $1" "not available in pacman" + fi + shift + done } appz_clean(){